update 2.2版本
This commit is contained in:
parent
e4fd7ec3e2
commit
b27c7e56d6
|
@ -4,7 +4,7 @@ set_target_properties(kydiskinfo PROPERTIES VERSION 2.0.0 SOVERSION 1)
|
|||
add_executable(test-getdiskinfo test/getdiskinfo.c)
|
||||
add_executable(test-getdisklist test/getdisklist.c)
|
||||
find_library(UDEV_LIB udev)
|
||||
target_link_libraries(kydiskinfo blkid kylog pthread systemd kyconf ${UDEV_LIB})
|
||||
target_link_libraries(kydiskinfo blkid kylog pthread systemd kyconf hd ${UDEV_LIB})
|
||||
target_link_libraries(test-getdiskinfo kydiskinfo)
|
||||
target_link_libraries(test-getdisklist kydiskinfo)
|
||||
# target_link_libraries(test-getdiskinfo kydiskinfo blkid kylog pthread systemd kyconf ${UDEV_LIB})
|
||||
|
@ -14,4 +14,4 @@ install(TARGETS kydiskinfo
|
|||
DESTINATION lib/kysdk/kysdk-system)
|
||||
|
||||
install(FILES libkydiskinfo.h
|
||||
DESTINATION include/kysdk/kysdk-system)
|
||||
DESTINATION include/kysdk/kysdk-system)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include "diskmarcos.h"
|
||||
#include <libkylog.h>
|
||||
#include <kerr.h>
|
||||
#include <sdkmarcos.h>
|
||||
#include <kysdk/kysdk-base/sdkmarcos.h>
|
||||
#include <blkid/blkid.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
|
@ -19,6 +19,7 @@
|
|||
#include <unistd.h>
|
||||
#include <libudev.h>
|
||||
#include <kysdk/kysdk-base/cstring-extension.h>
|
||||
#include "hd.h"
|
||||
|
||||
static int get_disk_fs(kdk_diskinfo *di)
|
||||
{
|
||||
|
@ -311,10 +312,13 @@ char** kdk_get_disklist()
|
|||
if (readlink(linkpath, targetpath, PATH_MAX) < 0)
|
||||
continue;
|
||||
|
||||
res = realloc(res, (counts + 1) * sizeof(char *));
|
||||
char **tmp = realloc(res, (counts + 1) * sizeof(char *));
|
||||
// FixMe: Memory Leak for res and dir
|
||||
ASSERT_NOT_NULL(res, NULL);
|
||||
|
||||
// ASSERT_NOT_NULL(res, NULL);
|
||||
if (!tmp) {
|
||||
goto err_out;
|
||||
}
|
||||
res = tmp;
|
||||
res[counts] = malloc(PATH_MAX * sizeof(char) + 1);
|
||||
res[counts][PATH_MAX + 1] = 0;
|
||||
|
||||
|
@ -342,11 +346,23 @@ char** kdk_get_disklist()
|
|||
#elif __win32
|
||||
#endif
|
||||
|
||||
res = realloc(res, (counts + 1) * sizeof(char *));
|
||||
char **tmp = realloc(res, (counts + 1) * sizeof(char *));
|
||||
// FixMe: Memory Leak
|
||||
ASSERT_NOT_NULL(res, NULL);
|
||||
// ASSERT_NOT_NULL(tmp, NULL);
|
||||
if(!tmp)
|
||||
goto err_out;
|
||||
res = tmp;
|
||||
res[counts] = NULL;
|
||||
return res;
|
||||
err_out:
|
||||
closedir(dir);
|
||||
while (counts)
|
||||
{
|
||||
free(res[counts - 1]);
|
||||
counts--;
|
||||
}
|
||||
free(res);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void kdk_free_disklist(char** disklist)
|
||||
|
@ -514,6 +530,352 @@ err_out:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
extern char** kdk_get_hard_disk()
|
||||
{
|
||||
char **ret = NULL;
|
||||
char **hard = realloc(ret, 512 * sizeof(char *));
|
||||
if (!hard)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
ret = hard;
|
||||
int count = 0;
|
||||
|
||||
hd_data_t *hd_data;
|
||||
hd_data = (hd_data_t *)calloc(1, sizeof *hd_data);
|
||||
if (!hd_data)
|
||||
{
|
||||
klog_err("%s 申请内存失败于%s", "kdk_hw_get_sound", "hd_data");
|
||||
free(hard);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hd_data->progress = NULL;
|
||||
hd_data->debug = ~(HD_DEB_DRIVER_INFO | HD_DEB_HDDB);
|
||||
|
||||
hd_t *hd, *hd0;
|
||||
hd0 = hd_list(hd_data, hw_disk, 1, NULL);
|
||||
for (hd = hd0; hd; hd = hd->next)
|
||||
{
|
||||
ret[count] = malloc(256 * sizeof(char) + 1);
|
||||
if(!ret[count])
|
||||
{
|
||||
free(ret);
|
||||
free(hd_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(hd->sysfs_device_link != NULL)
|
||||
{
|
||||
// printf("hd->unix_dev_name = %s\n", hd->unix_dev_name);
|
||||
if(hd->unix_dev_name)
|
||||
{
|
||||
strcpy(ret[count], hd->unix_dev_name);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret[count] = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* kdk_get_hard_disk_size(const char *hardname)
|
||||
{
|
||||
if(!hardname)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
char *hard_size = (char *)malloc(128*sizeof(char));
|
||||
if (!hard_size)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
kdk_diskinfo *sdainfo = kdk_get_diskinfo(hardname);
|
||||
if (!sdainfo)
|
||||
{
|
||||
free(hard_size);
|
||||
return NULL;
|
||||
}
|
||||
sprintf(hard_size,"%f",sdainfo->total_size_MiB);
|
||||
kdk_free_diskinfo(sdainfo);
|
||||
return hard_size;
|
||||
}
|
||||
|
||||
char* kdk_get_hard_fwrev(const char *hardname)
|
||||
{
|
||||
if(!hardname)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
char path[128] = "\0";
|
||||
char tmp[1024] = "\0";
|
||||
char fwrev[128] = "\0";
|
||||
char *hard_fwrev = (char *)malloc(128*sizeof(char));
|
||||
if (!hard_fwrev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kdk_diskinfo *sdainfo = kdk_get_diskinfo(hardname);
|
||||
if (!sdainfo)
|
||||
{
|
||||
free(hard_fwrev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!strcmp(sdainfo->fwrev, "None"))
|
||||
{
|
||||
sprintf(path, "smartctl -i %s", hardname);
|
||||
FILE *fp = popen(path, "r");
|
||||
if(!fp)
|
||||
{
|
||||
free(hard_fwrev);
|
||||
kdk_free_diskinfo(sdainfo);
|
||||
return NULL;
|
||||
}
|
||||
while (fgets(tmp, 1024, fp))
|
||||
{
|
||||
if (0 == strncmp(tmp, "Firmware Version:", 17))
|
||||
{
|
||||
sscanf(tmp, "%*s %*s %s", fwrev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pclose(fp);
|
||||
if(fwrev)
|
||||
{
|
||||
strcpy(hard_fwrev, fwrev);
|
||||
}
|
||||
else{
|
||||
free(hard_fwrev);
|
||||
kdk_free_diskinfo(sdainfo);
|
||||
return NULL;
|
||||
}
|
||||
}else{
|
||||
strcpy(hard_fwrev, sdainfo->fwrev);
|
||||
strstripspace(hard_fwrev);
|
||||
}
|
||||
kdk_free_diskinfo(sdainfo);
|
||||
return hard_fwrev;
|
||||
}
|
||||
|
||||
char* kdk_get_hard_type(const char *hardname)
|
||||
{
|
||||
if(!hardname)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
char *hard_type = (char *)malloc(128*sizeof(char));
|
||||
if (!hard_type)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kdk_diskinfo *sdainfo = kdk_get_diskinfo(hardname);
|
||||
if (!sdainfo)
|
||||
{
|
||||
free(hard_type);
|
||||
return NULL;
|
||||
}
|
||||
if(sdainfo->disk_type == 0)
|
||||
{
|
||||
strcpy(hard_type,"机械");
|
||||
}else{
|
||||
strcpy(hard_type,"固态");
|
||||
}
|
||||
kdk_free_diskinfo(sdainfo);
|
||||
return hard_type;
|
||||
}
|
||||
|
||||
char* kdk_get_hard_model(const char *hardname)
|
||||
{
|
||||
if(!hardname)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
char *hard_model = (char *)malloc(128*sizeof(char));
|
||||
if (!hard_model)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
char path[256] = "\0";
|
||||
char tmp[1024] = "\0";
|
||||
char *str = NULL;
|
||||
|
||||
sprintf(path, "smartctl -i %s", hardname);
|
||||
FILE *fd = popen(path, "r");
|
||||
if(!fd)
|
||||
{
|
||||
free(hard_model);
|
||||
return NULL;
|
||||
}
|
||||
while (fgets(tmp, 1024, fd))
|
||||
{
|
||||
if (0 == strncmp(tmp, "Model Number:", 13))
|
||||
{
|
||||
int tmp_pos = strlastof(tmp, ':');
|
||||
if (tmp_pos <= 0)
|
||||
tmp_pos = 0;
|
||||
str = tmp + tmp_pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pclose(fd);
|
||||
if (str)
|
||||
{
|
||||
strcpy(hard_model, str);
|
||||
strstripspace(hard_model);
|
||||
}
|
||||
return hard_model;
|
||||
}
|
||||
|
||||
char* kdk_get_hard_serial(const char *hardname)
|
||||
{
|
||||
if(!hardname)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
char *hard_serial = (char *)malloc(128*sizeof(char));
|
||||
if (!hard_serial)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
char line[256] = "\0";
|
||||
char path[128] = "\0";
|
||||
char tmp[1024] = "\0";
|
||||
char serial[128] = "\0";
|
||||
char *str = NULL;
|
||||
char name[128] = "\0";
|
||||
char hard_name[128] = "\0";
|
||||
strcpy(hard_name, hardname);
|
||||
|
||||
int pos = strlastof(hardname, '/');
|
||||
if (pos <= 0)
|
||||
pos = 0;
|
||||
char *dn = hardname + pos;
|
||||
|
||||
sprintf(path, "/sys/class/block/%s/device/serial", dn);
|
||||
|
||||
FILE *fp = fopen(path, "r");
|
||||
if(fp)
|
||||
{
|
||||
fgets(line, sizeof(line), fp);
|
||||
fclose(fp);
|
||||
if(line[0] != '\0')
|
||||
{
|
||||
strcpy(hard_serial, line);
|
||||
strstripspace(hard_serial);
|
||||
}
|
||||
}
|
||||
else{
|
||||
memset(path, 0, sizeof(path));
|
||||
sprintf(path, "smartctl -i %s", hardname);
|
||||
FILE *fp = popen(path, "r");
|
||||
if(!fp)
|
||||
{
|
||||
free(hard_serial);
|
||||
return NULL;
|
||||
}
|
||||
while (fgets(tmp, 1024, fp))
|
||||
{
|
||||
if (0 == strncmp(tmp, "Serial Number:", 14))
|
||||
{
|
||||
int tmp_pos = strlastof(tmp, ':');
|
||||
if (tmp_pos <= 0)
|
||||
tmp_pos = 0;
|
||||
str = tmp + tmp_pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pclose(fp);
|
||||
if (str)
|
||||
{
|
||||
strcpy(hard_serial, str);
|
||||
strstripspace(hard_serial);
|
||||
}
|
||||
else{
|
||||
hd_data_t *hd_data;
|
||||
hd_data = (hd_data_t *)calloc(1, sizeof *hd_data);
|
||||
if (!hd_data)
|
||||
{
|
||||
free(hard_serial);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hd_data->progress = NULL;
|
||||
hd_data->debug = ~(HD_DEB_DRIVER_INFO | HD_DEB_HDDB);
|
||||
int i = 0;
|
||||
hd_t *hd, *hd0;
|
||||
hd0 = hd_list(hd_data, hw_disk, 1, NULL);
|
||||
for (hd = hd0; hd; hd = hd->next)
|
||||
{
|
||||
sprintf(name, "%s", hd->unix_dev_name);
|
||||
if(strcmp(name, hard_name) == 0)
|
||||
{
|
||||
if(hd->serial)
|
||||
{
|
||||
strcpy(hard_serial, hd->serial);
|
||||
}
|
||||
else{
|
||||
free(hard_serial);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return hard_serial;
|
||||
}
|
||||
|
||||
char* kdk_get_hard_vendor(const char *hardname)
|
||||
{
|
||||
if(!hardname)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
char *hard_vendor = (char *)malloc(128*sizeof(char));
|
||||
if (!hard_vendor)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
char name[64] = "\0";
|
||||
struct HWInfo *result = NULL;
|
||||
|
||||
hd_data_t *hd_data;
|
||||
hd_data = (hd_data_t *)calloc(1, sizeof *hd_data);
|
||||
if (!hd_data)
|
||||
{
|
||||
free(hard_vendor);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hd_data->progress = NULL;
|
||||
hd_data->debug = ~(HD_DEB_DRIVER_INFO | HD_DEB_HDDB);
|
||||
|
||||
hd_t *hd, *hd0;
|
||||
hd0 = hd_list(hd_data, hw_disk, 1, NULL);
|
||||
for (hd = hd0; hd; hd = hd->next)
|
||||
{
|
||||
sprintf(name, "%s", hd->unix_dev_name);
|
||||
if(strcmp(name, hardname) == 0)
|
||||
{
|
||||
if(hd->vendor.name)
|
||||
{
|
||||
strcpy(hard_vendor, hd->vendor.name);
|
||||
}
|
||||
else if(hd->sub_vendor.name)
|
||||
{
|
||||
strcpy(hard_vendor, hd->sub_vendor.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(strstr(hard_vendor, "ST"))
|
||||
{
|
||||
strcpy(hard_vendor, "Seagate");
|
||||
}
|
||||
return hard_vendor;
|
||||
}
|
||||
|
||||
void kdk_free_diskinfo(kdk_diskinfo *disk)
|
||||
{
|
||||
SAFE_FREE(disk->name);
|
||||
|
|
|
@ -95,6 +95,61 @@ extern void kdk_free_disklist(char** disklist);
|
|||
*/
|
||||
extern kdk_diskinfo *kdk_get_diskinfo(const char *diskname);
|
||||
|
||||
/**
|
||||
* @brief 获取系统接入所有硬盘
|
||||
*
|
||||
* @return char** 硬盘名称
|
||||
*/
|
||||
extern char** kdk_get_hard_disk();
|
||||
|
||||
/**
|
||||
* @brief 获取硬盘大小
|
||||
*
|
||||
* @param hardname 指定磁盘名称,应当是例如/dev/sda这种绝对路径
|
||||
* @return char* 硬盘大小,失败返回NULL。返回的字符串需要被 free 释放
|
||||
*/
|
||||
extern char* kdk_get_hard_disk_size(const char *hardname);
|
||||
|
||||
/**
|
||||
* @brief 获取硬盘固态版本
|
||||
*
|
||||
* @param hardname 指定磁盘名称,应当是例如/dev/sda这种绝对路径
|
||||
* @return char* 硬盘固态版本,失败返回NULL。返回的字符串需要被 free 释放
|
||||
*/
|
||||
extern char* kdk_get_hard_fwrev(const char *hardname);
|
||||
|
||||
/**
|
||||
* @brief 获取硬盘类型
|
||||
*
|
||||
* @param hardname 指定磁盘名称,应当是例如/dev/sda这种绝对路径
|
||||
* @return char* 硬盘类型,失败返回NULL。返回的字符串需要被 free 释放
|
||||
*/
|
||||
extern char* kdk_get_hard_type(const char *hardname);
|
||||
|
||||
/**
|
||||
* @brief 获取硬盘型号
|
||||
*
|
||||
* @param hardname 指定磁盘名称,应当是例如/dev/sda这种绝对路径
|
||||
* @return char* 硬盘型号,失败返回NULL。返回的字符串需要被 free 释放
|
||||
*/
|
||||
extern char* kdk_get_hard_model(const char *hardname);
|
||||
|
||||
/**
|
||||
* @brief 获取硬盘序列号
|
||||
*
|
||||
* @param hardname 指定磁盘名称,应当是例如/dev/sda这种绝对路径
|
||||
* @return char* 硬盘序列号,失败返回NULL。返回的字符串需要被 free 释放
|
||||
*/
|
||||
extern char* kdk_get_hard_serial(const char *hardname);
|
||||
|
||||
/**
|
||||
* @brief 获取硬盘厂商
|
||||
*
|
||||
* @param hardname 指定磁盘名称,应当是例如/dev/sda这种绝对路径
|
||||
* @return char* 硬盘厂商,失败返回NULL。返回的字符串需要被 free 释放
|
||||
*/
|
||||
extern char* kdk_get_hard_vendor(const char *hardname);
|
||||
|
||||
/**
|
||||
* @brief 释放由kdk_get_diskinfo返回的磁盘信息结构体
|
||||
*
|
||||
|
@ -106,4 +161,4 @@ extern void kdk_free_diskinfo(kdk_diskinfo *disk);
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "../libkydiskinfo.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void display_disk_info(kdk_diskinfo *di)
|
||||
{
|
||||
|
@ -43,5 +44,39 @@ int main()
|
|||
}
|
||||
kdk_free_disklist(disklist);
|
||||
|
||||
|
||||
char **di = kdk_get_hard_disk();
|
||||
size_t num = 0;
|
||||
while (di[num])
|
||||
{
|
||||
printf("No. %ld\t %s\n", num + 1, di[num]);
|
||||
char *res = kdk_get_hard_disk_size(di[num]);
|
||||
printf("容量 = %s\n", res);
|
||||
free(res);
|
||||
|
||||
res = kdk_get_hard_fwrev(di[num]);
|
||||
printf("固态版本 = %s\n", res);
|
||||
free(res);
|
||||
|
||||
res = kdk_get_hard_vendor(di[num]);
|
||||
printf("厂商 = %s\n", res);
|
||||
free(res);
|
||||
|
||||
res = kdk_get_hard_type(di[num]);
|
||||
printf("类型 = %s\n", res);
|
||||
free(res);
|
||||
|
||||
res = kdk_get_hard_model(di[num]);
|
||||
printf("型号 = %s\n", res);
|
||||
free(res);
|
||||
|
||||
res =kdk_get_hard_serial(di[num]);
|
||||
printf("序列号 = %s\n", res);
|
||||
free(res);
|
||||
|
||||
num ++;
|
||||
}
|
||||
kdk_free_disklist(di);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,8 +12,13 @@ add_executable(kyprinterprint-test test/kyprinterprint-test.c)
|
|||
add_executable(kyusb-test test/kyusb-test.c)
|
||||
add_executable(kybios-test test/kybios-test.c)
|
||||
add_executable(kyboard-test test/kyboard-test.c)
|
||||
add_executable(kydisplay-test test/kydisplay-test.c)
|
||||
add_executable(kyedid-test test/kyedid-test.c)
|
||||
add_executable(kybluetooth-test test/kybluetooth-test.c)
|
||||
add_executable(kyfan-test test/kyfan-test.c)
|
||||
add_executable(kyhw-test test/kyhw-test.c)
|
||||
# 额外链接的库在这一行
|
||||
target_link_libraries(kyhw kylog kyconf pthread systemd cups curl udev ${GLIB_LIBRARIES})
|
||||
target_link_libraries(kyhw kylog kyconf pthread systemd cups curl udev X11 Xrandr bluetooth sensors hd pci gobject-2.0 dbus-glib-1 ${GLIB_LIBRARIES})
|
||||
target_link_libraries(kyprinterprint-test kyhw)
|
||||
target_link_libraries(kyprinterlist-test kyhw)
|
||||
target_link_libraries(kync-test kyhw)
|
||||
|
@ -21,6 +26,11 @@ target_link_libraries(kycpu-test kyhw)
|
|||
target_link_libraries(kyusb-test kyhw)
|
||||
target_link_libraries(kybios-test kyhw)
|
||||
target_link_libraries(kyboard-test kyhw)
|
||||
target_link_libraries(kydisplay-test kyhw)
|
||||
target_link_libraries(kyedid-test kyhw)
|
||||
target_link_libraries(kybluetooth-test kyhw)
|
||||
target_link_libraries(kyfan-test kyhw)
|
||||
target_link_libraries(kyhw-test kyhw)
|
||||
|
||||
install(TARGETS kyhw
|
||||
DESTINATION lib/kysdk/kysdk-system)
|
||||
|
@ -42,3 +52,18 @@ install(FILES libkyboard.h
|
|||
|
||||
install(FILES libkyusb.h
|
||||
DESTINATION include/kysdk/kysdk-system)
|
||||
|
||||
install(FILES libkydisplay.h
|
||||
DESTINATION include/kysdk/kysdk-system)
|
||||
|
||||
install(FILES libkyedid.h
|
||||
DESTINATION include/kysdk/kysdk-system)
|
||||
|
||||
install(FILES libkybluetooth.h
|
||||
DESTINATION include/kysdk/kysdk-system)
|
||||
|
||||
install(FILES libkyfan.h
|
||||
DESTINATION include/kysdk/kysdk-system)
|
||||
|
||||
install(FILES libkyhw.h
|
||||
DESTINATION include/kysdk/kysdk-system)
|
||||
|
|
|
@ -0,0 +1,446 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdint.h>
|
||||
#include <bluetooth/bluetooth.h>
|
||||
#include <bluetooth/hci.h>
|
||||
#include <bluetooth/hci_lib.h>
|
||||
#include "libkybluetooth.h"
|
||||
#include "hd.h"
|
||||
|
||||
int** kdk_bluetooth_get_device_id()
|
||||
{
|
||||
static struct hci_dev_info di;
|
||||
int **id = (int *)malloc(sizeof(int) * 16);
|
||||
if(!id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
struct hci_dev_list_req *dl;
|
||||
struct hci_dev_req *dr;
|
||||
int i, ctl;
|
||||
if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) {
|
||||
free(id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(dl = malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t)))) {
|
||||
free(id);
|
||||
return 0;
|
||||
}
|
||||
dl->dev_num = HCI_MAX_DEV;
|
||||
dr = dl->dev_req;
|
||||
|
||||
if (ioctl(ctl, HCIGETDEVLIST, (void *) dl) < 0) {
|
||||
free(dl);
|
||||
free(id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i< dl->dev_num; i++) {
|
||||
|
||||
di.dev_id = (dr+i)->dev_id;
|
||||
id[i] = malloc(sizeof(int) * 16);
|
||||
if(!id[i])
|
||||
{
|
||||
free(dl);
|
||||
free(id);
|
||||
return 0;
|
||||
}
|
||||
id[i] = di.dev_id;
|
||||
}
|
||||
// i = i + 1;
|
||||
id[i] = 0;
|
||||
return id;
|
||||
}
|
||||
|
||||
char *kdk_bluetooth_get_manufacturer(int id)
|
||||
{
|
||||
char *manufacturer = (char *)malloc(64 * sizeof(char));
|
||||
if (!manufacturer)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
char name[64] = "\0";
|
||||
|
||||
hd_data_t *hd_data;
|
||||
hd_data = (hd_data_t *)calloc(1, sizeof *hd_data);
|
||||
if (!hd_data)
|
||||
{
|
||||
free(manufacturer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hd_data->progress = NULL;
|
||||
hd_data->debug = ~(HD_DEB_DRIVER_INFO | HD_DEB_HDDB);
|
||||
int i = 0;
|
||||
hd_t *hd, *hd0;
|
||||
hd0 = hd_list(hd_data, hw_bluetooth, 1, NULL);
|
||||
for (hd = hd0; hd; hd = hd->next)
|
||||
{
|
||||
if(i == id)
|
||||
{
|
||||
if(hd->vendor.name)
|
||||
{
|
||||
strcpy(name, hd->vendor.name);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if(name[0] == '\0')
|
||||
{
|
||||
free(manufacturer);
|
||||
return NULL;
|
||||
}
|
||||
strcpy(manufacturer, name);
|
||||
return manufacturer;
|
||||
}
|
||||
|
||||
char *kdk_bluetooth_get_dev_version(int id)
|
||||
{
|
||||
char *version = (char *)malloc(12 * sizeof(char));
|
||||
if (!version)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
char name[64] = "\0";
|
||||
|
||||
hd_data_t *hd_data;
|
||||
hd_data = (hd_data_t *)calloc(1, sizeof *hd_data);
|
||||
if (!hd_data)
|
||||
{
|
||||
free(version);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hd_data->progress = NULL;
|
||||
hd_data->debug = ~(HD_DEB_DRIVER_INFO | HD_DEB_HDDB);
|
||||
|
||||
int i = 0;
|
||||
hd_t *hd, *hd0;
|
||||
hd0 = hd_list(hd_data, hw_bluetooth, 1, NULL);
|
||||
for (hd = hd0; hd; hd = hd->next)
|
||||
{
|
||||
if(i == id)
|
||||
{
|
||||
if(hd->revision.name)
|
||||
{
|
||||
strcpy(name, hd->revision.name);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if(name[0] == '\0')
|
||||
{
|
||||
int ctl;
|
||||
static struct hci_dev_info di;
|
||||
struct hci_version ver;
|
||||
int dd;
|
||||
char tmp[30] = "\0";
|
||||
|
||||
if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0)
|
||||
{
|
||||
free(version);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ioctl(ctl, HCIGETDEVINFO, (void *)&di))
|
||||
{
|
||||
free(version);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// print_dev_info(ctl, &di);
|
||||
dd = hci_open_dev(di.dev_id);
|
||||
if (dd < 0)
|
||||
{
|
||||
free(version);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (hci_read_local_version(dd, &ver, 1000) < 0)
|
||||
{
|
||||
free(version);
|
||||
return NULL;
|
||||
}
|
||||
if(ver.hci_rev)
|
||||
{
|
||||
sprintf(tmp, "0x%x", ver.hci_rev);
|
||||
strcpy(version, tmp);
|
||||
}
|
||||
|
||||
hci_close_dev(dd);
|
||||
}
|
||||
else{
|
||||
strcpy(version, name);
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
char* kdk_bluetooth_get_name(int id)
|
||||
{
|
||||
int ctl;
|
||||
static struct hci_dev_info di;
|
||||
int dd;
|
||||
char name[249];
|
||||
int i;
|
||||
char *version = (char *)malloc(sizeof(char) * 64);
|
||||
|
||||
if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0)
|
||||
{
|
||||
free(version);
|
||||
return NULL;
|
||||
}
|
||||
di.dev_id = id;
|
||||
|
||||
if (ioctl(ctl, HCIGETDEVINFO, (void *)&di))
|
||||
{
|
||||
free(version);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dd = hci_open_dev(di.dev_id);
|
||||
if (dd < 0) {
|
||||
free(version);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (hci_read_local_name(dd, sizeof(name), name, 1000) < 0) {
|
||||
free(version);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < 248 && name[i]; i++) {
|
||||
if ((unsigned char) name[i] < 32 || name[i] == 127)
|
||||
name[i] = '.';
|
||||
}
|
||||
|
||||
name[248] = '\0';
|
||||
strcpy(version, name);
|
||||
hci_close_dev(dd);
|
||||
return version;
|
||||
}
|
||||
|
||||
char* kdk_bluetooth_get_address(int id)
|
||||
{
|
||||
int ctl;
|
||||
static struct hci_dev_info di;
|
||||
char addr[18];
|
||||
char *address = (char *)malloc(sizeof(char) * 64);
|
||||
|
||||
if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0)
|
||||
{
|
||||
free(address);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
di.dev_id = id;
|
||||
|
||||
if (ioctl(ctl, HCIGETDEVINFO, (void *)&di))
|
||||
{
|
||||
free(address);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ba2str(&di.bdaddr, addr);
|
||||
if(addr)
|
||||
{
|
||||
strcpy(address, addr);
|
||||
return address;
|
||||
}
|
||||
else{
|
||||
free(address);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
char* kdk_bluetooth_get_link_mode(int id)
|
||||
{
|
||||
char *str;
|
||||
int ctl;
|
||||
static struct hci_dev_info di;
|
||||
char *link_mode = (char *)malloc(sizeof(char) * 64);
|
||||
|
||||
if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0)
|
||||
{
|
||||
free(link_mode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
di.dev_id = id;
|
||||
|
||||
if (ioctl(ctl, HCIGETDEVINFO, (void *)&di))
|
||||
{
|
||||
free(link_mode);
|
||||
return NULL;
|
||||
}
|
||||
str = hci_lmtostr(di.link_mode);
|
||||
if(str)
|
||||
{
|
||||
strcpy(link_mode, str);
|
||||
bt_free(str);
|
||||
return link_mode;
|
||||
}
|
||||
else{
|
||||
free(link_mode);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
char* kdk_bluetooth_get_link_policy(int id)
|
||||
{
|
||||
int ctl;
|
||||
static struct hci_dev_info di;
|
||||
char *link_policy = (char *)malloc(sizeof(char) * 64);
|
||||
|
||||
if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0)
|
||||
{
|
||||
free(link_policy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
di.dev_id = id;
|
||||
|
||||
if (ioctl(ctl, HCIGETDEVINFO, (void *)&di))
|
||||
{
|
||||
free(link_policy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(link_policy, hci_lptostr(di.link_policy));
|
||||
return link_policy;
|
||||
}
|
||||
|
||||
char* kdk_bluetooth_get_bus(int id)
|
||||
{
|
||||
int ctl;
|
||||
static struct hci_dev_info di;
|
||||
char *bus = (char *)malloc(sizeof(char) * 64);
|
||||
|
||||
if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0)
|
||||
{
|
||||
free(bus);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
di.dev_id = id;
|
||||
|
||||
if (ioctl(ctl, HCIGETDEVINFO, (void *)&di))
|
||||
{
|
||||
free(bus);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(bus, hci_bustostr(di.type & 0x0f));
|
||||
return bus;
|
||||
}
|
||||
|
||||
char* kdk_bluetooth_get_scomtu(int id)
|
||||
{
|
||||
int ctl;
|
||||
static struct hci_dev_info di;
|
||||
char addr[18];
|
||||
char tmp[20] = "\0";
|
||||
char *scomtu = (char *)malloc(sizeof(char) * 64);
|
||||
|
||||
if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0)
|
||||
{
|
||||
free(scomtu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
di.dev_id = id;
|
||||
|
||||
if (ioctl(ctl, HCIGETDEVINFO, (void *)&di))
|
||||
{
|
||||
free(scomtu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ba2str(&di.bdaddr, addr);
|
||||
sprintf(tmp, "%d:%d", di.sco_mtu, di.sco_pkts);
|
||||
strcpy(scomtu, tmp);
|
||||
return scomtu;
|
||||
}
|
||||
|
||||
char* kdk_bluetooth_get_alcmtu(int id)
|
||||
{
|
||||
int ctl;
|
||||
static struct hci_dev_info di;
|
||||
char tmp[20] = "\0";
|
||||
char *alcmtu = (char *)malloc(sizeof(char) * 64);
|
||||
|
||||
if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0)
|
||||
{
|
||||
free(alcmtu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
di.dev_id = id;
|
||||
|
||||
if (ioctl(ctl, HCIGETDEVINFO, (void *)&di))
|
||||
{
|
||||
free(alcmtu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sprintf(tmp, "%d:%d", di.acl_mtu, di.acl_pkts);
|
||||
strcpy(alcmtu, tmp);
|
||||
return alcmtu;
|
||||
}
|
||||
|
||||
char* kdk_bluetooth_get_packettype(int id)
|
||||
{
|
||||
char *str;
|
||||
int ctl;
|
||||
static struct hci_dev_info di;
|
||||
|
||||
char *packettype = (char *)malloc(sizeof(char) * 64);
|
||||
|
||||
if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0)
|
||||
{
|
||||
free(packettype);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
di.dev_id = id;
|
||||
|
||||
if (ioctl(ctl, HCIGETDEVINFO, (void *)&di))
|
||||
{
|
||||
free(packettype);
|
||||
return NULL;
|
||||
}
|
||||
str = hci_ptypetostr(di.pkt_type);
|
||||
strcpy(packettype, str);
|
||||
bt_free(str);
|
||||
return packettype;
|
||||
}
|
||||
|
||||
char* kdk_bluetooth_get_features(int id)
|
||||
{
|
||||
int ctl;
|
||||
static struct hci_dev_info di;
|
||||
char tmp[50] = "\0";
|
||||
char *features = (char *)malloc(sizeof(char) * 64);
|
||||
|
||||
if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0)
|
||||
{
|
||||
free(features);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
di.dev_id = id;
|
||||
|
||||
if (ioctl(ctl, HCIGETDEVINFO, (void *)&di))
|
||||
{
|
||||
free(features);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sprintf(tmp, "0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x",
|
||||
di.features[0], di.features[1], di.features[2], di.features[3],
|
||||
di.features[4], di.features[5], di.features[6], di.features[7]);
|
||||
strcpy(features, tmp);
|
||||
return features;
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
#ifndef LIBKYBLUETOOTH_H
|
||||
#define LIBKYBLUETOOTH_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 获取蓝牙的设备id
|
||||
*
|
||||
* @return const int** 蓝牙的设备id
|
||||
*/
|
||||
extern int** kdk_bluetooth_get_device_id();
|
||||
|
||||
/**
|
||||
* @brief 获取蓝牙的制造商
|
||||
*
|
||||
* @param num 蓝牙设备的个数,从0开始,0代表1个,以此类推。
|
||||
* @return const char* 蓝牙的制造商
|
||||
*/
|
||||
extern char* kdk_bluetooth_get_manufacturer(int num);
|
||||
|
||||
/**
|
||||
* @brief 获取蓝牙的设备版本
|
||||
*
|
||||
* @param num 蓝牙设备的个数,从0开始,0代表1个,以此类推。
|
||||
* @return const char* 蓝牙的设备版本
|
||||
*/
|
||||
extern char* kdk_bluetooth_get_dev_version(int num);
|
||||
|
||||
/**
|
||||
* @brief 获取蓝牙的名称
|
||||
*
|
||||
* @param id 蓝牙的设备id
|
||||
* @return const char* 蓝牙的名称
|
||||
*/
|
||||
extern char* kdk_bluetooth_get_name(int id);
|
||||
|
||||
/**
|
||||
* @brief 获取蓝牙的地址
|
||||
*
|
||||
* @param id 蓝牙的设备id
|
||||
* @return const char* 蓝牙的地址
|
||||
*/
|
||||
extern char* kdk_bluetooth_get_address(int id);
|
||||
|
||||
/**
|
||||
* @brief 获取蓝牙的连接模式
|
||||
*
|
||||
* @param id 蓝牙的设备id
|
||||
* @return const char* 蓝牙的连接模式
|
||||
*/
|
||||
extern char* kdk_bluetooth_get_link_mode(int id);
|
||||
|
||||
/**
|
||||
* @brief 获取蓝牙的连接策略
|
||||
*
|
||||
* @param id 蓝牙的设备id
|
||||
* @return const char* 蓝牙的连接策略
|
||||
*/
|
||||
extern char* kdk_bluetooth_get_link_policy(int id);
|
||||
|
||||
/**
|
||||
* @brief 获取蓝牙的总线
|
||||
*
|
||||
* @param id 蓝牙的设备id
|
||||
* @return const char* 蓝牙的总线
|
||||
*/
|
||||
extern char* kdk_bluetooth_get_bus(int id);
|
||||
|
||||
/**
|
||||
* @brief 获取蓝牙的SCO MTU
|
||||
*
|
||||
* @param id 蓝牙的设备id
|
||||
* @return const char* 蓝牙的SCO MTU
|
||||
*/
|
||||
extern char* kdk_bluetooth_get_scomtu(int id);
|
||||
|
||||
/**
|
||||
* @brief 获取蓝牙的ALC MTU
|
||||
*
|
||||
* @param id 蓝牙的设备id
|
||||
* @return const char* 蓝牙的ALC MTU
|
||||
*/
|
||||
extern char* kdk_bluetooth_get_alcmtu(int id);
|
||||
|
||||
/**
|
||||
* @brief 获取蓝牙的数据包类型
|
||||
*
|
||||
* @param id 蓝牙的设备id
|
||||
* @return const char* 蓝牙的数据包类型
|
||||
*/
|
||||
extern char* kdk_bluetooth_get_packettype(int id);
|
||||
|
||||
/**
|
||||
* @brief 获取蓝牙的特征
|
||||
*
|
||||
* @param id 蓝牙的设备id
|
||||
* @return const char* 蓝牙的特征
|
||||
*/
|
||||
extern char* kdk_bluetooth_get_features(int id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -2,7 +2,7 @@
|
|||
#include <cstring-extension.h>
|
||||
#include <errno.h>
|
||||
#include <libkylog.h>
|
||||
#include <sdkmarcos.h>
|
||||
#include <kysdk/kysdk-base/sdkmarcos.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
@ -372,6 +372,7 @@ static void _get_cpu_info()
|
|||
cpuinf->vendor = strdup("loongson");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (cpuinf->flags)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
#include "libkydisplay.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <cstring-extension.h>
|
||||
#include <errno.h>
|
||||
#include <libkylog.h>
|
||||
|
||||
char *display_get_info(char *str)
|
||||
{
|
||||
char *display = (char*)malloc(sizeof(char) * 512);
|
||||
if (!display)
|
||||
{
|
||||
klog_err("内存申请失败:%s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
memset(display, 0, sizeof(display));
|
||||
char buf[1024] = {0};
|
||||
memset(buf, 0, sizeof(buf));
|
||||
int i = 0;
|
||||
char *buff[3], *p = NULL;
|
||||
FILE *pipeLine = popen("lshw -C display", "r");
|
||||
if (!pipeLine)
|
||||
{
|
||||
free(display);
|
||||
return NULL;
|
||||
}
|
||||
if (__glibc_likely(pipeLine != NULL))
|
||||
{
|
||||
while (fgets(buf, sizeof(buf), pipeLine))
|
||||
{
|
||||
if(strstr(buf, str))
|
||||
{
|
||||
p = strtok(buf, ":");
|
||||
while(p)
|
||||
{
|
||||
buff[i] = p;
|
||||
i++;
|
||||
p = strtok(NULL,"");
|
||||
}
|
||||
strcpy(display, buff[1]);
|
||||
strstripspace(display);
|
||||
}
|
||||
}
|
||||
}
|
||||
pclose(pipeLine);
|
||||
return display;
|
||||
}
|
||||
|
||||
char* kdk_display_get_vendor()
|
||||
{
|
||||
return display_get_info("vendor");
|
||||
}
|
||||
|
||||
char* kdk_display_get_product()
|
||||
{
|
||||
return display_get_info("product");
|
||||
}
|
||||
|
||||
char* kdk_display_get_description()
|
||||
{
|
||||
return display_get_info("description");
|
||||
}
|
||||
|
||||
char* kdk_display_get_physical_id()
|
||||
{
|
||||
return display_get_info("physical id");
|
||||
}
|
||||
|
||||
char* kdk_display_get_bus_info()
|
||||
{
|
||||
return display_get_info("bus info");
|
||||
}
|
||||
|
||||
char* kdk_display_get_version()
|
||||
{
|
||||
return display_get_info("version");
|
||||
}
|
||||
|
||||
char* kdk_display_get_width()
|
||||
{
|
||||
return display_get_info("width");
|
||||
}
|
||||
|
||||
char* kdk_display_get_clock()
|
||||
{
|
||||
return display_get_info("clock");
|
||||
}
|
||||
|
||||
char* kdk_display_get_capabilities()
|
||||
{
|
||||
return display_get_info("capabilities");
|
||||
}
|
||||
|
||||
char* kdk_display_get_configuration()
|
||||
{
|
||||
return display_get_info("configuration");
|
||||
}
|
||||
|
||||
char* kdk_display_get_resources()
|
||||
{
|
||||
return display_get_info("resources");
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
#ifndef LIBKYDISPLAY_H
|
||||
#define LIBKYDISPLAY_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 获取显卡的制造商
|
||||
*
|
||||
* @return char* 显卡的制造商
|
||||
*/
|
||||
extern char* kdk_display_get_vendor();
|
||||
|
||||
/**
|
||||
* @brief 获取显卡的型号
|
||||
*
|
||||
* @return char* 显卡的型号
|
||||
*/
|
||||
extern char* kdk_display_get_product();
|
||||
|
||||
/**
|
||||
* @brief 获取显卡的说明
|
||||
*
|
||||
* @return char* 显卡的说明
|
||||
*/
|
||||
extern char* kdk_display_get_description();
|
||||
|
||||
/**
|
||||
* @brief 获取显卡的物理id
|
||||
*
|
||||
* @return char* 显卡的物理id
|
||||
*/
|
||||
extern char* kdk_display_get_physical_id();
|
||||
|
||||
/**
|
||||
* @brief 获取显卡的总线地址
|
||||
*
|
||||
* @return char* 显卡的总线地址
|
||||
*/
|
||||
extern char* kdk_display_get_bus_info();
|
||||
|
||||
/**
|
||||
* @brief 获取显卡的设备版本
|
||||
*
|
||||
* @return char* 显卡的设备版本
|
||||
*/
|
||||
extern char* kdk_display_get_version();
|
||||
|
||||
/**
|
||||
* @brief 获取显卡的数据宽度
|
||||
*
|
||||
* @return char* 显卡的数据宽度
|
||||
*/
|
||||
extern char* kdk_display_get_width();
|
||||
|
||||
/**
|
||||
* @brief 获取显卡的频率
|
||||
*
|
||||
* @return char* 显卡的频率
|
||||
*/
|
||||
extern char* kdk_display_get_clock();
|
||||
|
||||
/**
|
||||
* @brief 获取显卡的功能
|
||||
*
|
||||
* @return char* 显卡的功能
|
||||
*/
|
||||
extern char* kdk_display_get_capabilities();
|
||||
|
||||
/**
|
||||
* @brief 获取显卡的配置
|
||||
*
|
||||
* @return char* 显卡的配置
|
||||
*/
|
||||
extern char* kdk_display_get_configuration();
|
||||
|
||||
/**
|
||||
* @brief 获取显卡的资源
|
||||
*
|
||||
* @return char* 显卡的资源
|
||||
*/
|
||||
extern char* kdk_display_get_resources();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,112 @@
|
|||
#ifndef LIBKYEDID_H
|
||||
#define LIBKYEDID_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 获取显示器的当前接口
|
||||
*
|
||||
* @return char** 显示器的当前接口
|
||||
*/
|
||||
extern char** kdk_edid_get_interface();
|
||||
|
||||
/**
|
||||
* @brief 获取显示器的伽马值
|
||||
*
|
||||
* @return float 显示器的伽马值
|
||||
*/
|
||||
extern float kdk_edid_get_gamma(char *name);
|
||||
|
||||
/**
|
||||
* @brief 获取显示器的屏幕尺寸(英寸)
|
||||
*
|
||||
* @return float 显示器的屏幕尺寸(英寸)
|
||||
*/
|
||||
extern float kdk_edid_get_size(char *name);
|
||||
|
||||
/**
|
||||
* @brief 获取显示器的最大分辨率
|
||||
*
|
||||
* @return char* 显示器的最大分辨率
|
||||
*/
|
||||
extern char* kdk_edid_get_max_resolution(char *name);
|
||||
|
||||
/**
|
||||
* @brief 获取显示器的显示器型号
|
||||
*
|
||||
* @return char* 显示器的显示器型号
|
||||
*/
|
||||
extern char* kdk_edid_get_model(char *name);
|
||||
|
||||
/**
|
||||
* @brief 获取显示器的可视面积
|
||||
*
|
||||
* @return char* 显示器的可视面积
|
||||
*/
|
||||
extern char* kdk_edid_get_visible_area(char *name);
|
||||
|
||||
/**
|
||||
* @brief 获取显示器的厂商
|
||||
*
|
||||
* @return char* 显示器的厂商
|
||||
*/
|
||||
extern char* kdk_edid_get_manufacturer(char *name);
|
||||
|
||||
/**
|
||||
* @brief 获取显示器的生产日期/周
|
||||
*
|
||||
* @return char* 显示器的生产日期/周
|
||||
*/
|
||||
extern int kdk_edid_get_week(char *name);
|
||||
|
||||
/**
|
||||
* @brief 获取显示器的生产日期/年
|
||||
*
|
||||
* @return char* 显示器的生产日期/年
|
||||
*/
|
||||
extern int kdk_edid_get_year(char *name);
|
||||
|
||||
/**
|
||||
* @brief 获取是否是主显示器(是/否)
|
||||
*
|
||||
* @return int 是否是主显示器,1为是,0为否
|
||||
*/
|
||||
extern int kdk_edid_get_primary(char *name);
|
||||
|
||||
/**
|
||||
* @brief 获取分辨率
|
||||
*
|
||||
* @return char* 分辨率
|
||||
*/
|
||||
extern char* kdk_edid_get_resolution(char *name);
|
||||
|
||||
/**
|
||||
* @brief 获取图像高宽比
|
||||
*
|
||||
* @return char* 图像高宽比
|
||||
*/
|
||||
extern char* kdk_edid_get_ratio(char *name);
|
||||
|
||||
/**
|
||||
* @brief 获取显示器edid未解析的字符串
|
||||
*
|
||||
* @return char* edid未解析的字符串
|
||||
*/
|
||||
extern char* kdk_edid_get_character(char *name);
|
||||
|
||||
/**
|
||||
* @brief 用于回收字符串列表
|
||||
*
|
||||
* @param ptr 字符串列表
|
||||
*/
|
||||
extern inline void kdk_edid_freeall(char **ptr);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,229 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sensors/sensors.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <langinfo.h>
|
||||
#include "libkyfan.h"
|
||||
|
||||
static char *print_label(const char *label, int space)
|
||||
{
|
||||
char tmp[20] = "\0";
|
||||
char *ret = (char *)malloc(sizeof(char) * 20);
|
||||
// printf("%s:%*s", label, space - len, "");
|
||||
sprintf(tmp, "%s:", label);
|
||||
strcpy(ret, tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int get_input_value(const sensors_chip_name *name,
|
||||
const sensors_subfeature *sub,
|
||||
double *val)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = sensors_get_value(name, sub->number, val);
|
||||
return err;
|
||||
}
|
||||
|
||||
static char* print_chip_fan(const sensors_chip_name *name,
|
||||
const sensors_feature *feature,
|
||||
int label_size)
|
||||
{
|
||||
const sensors_subfeature *sf;
|
||||
double val;
|
||||
char *label;
|
||||
char tmp[20] = "\0";
|
||||
char *fan = (char *)malloc(sizeof(char) * 64);
|
||||
if(!fan)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(label = sensors_get_label(name, feature)))
|
||||
{
|
||||
free(fan);
|
||||
return NULL;
|
||||
}
|
||||
char *ret = print_label(label, label_size);
|
||||
free(label);
|
||||
|
||||
sf = sensors_get_subfeature(name, feature,
|
||||
SENSORS_SUBFEATURE_FAN_FAULT);
|
||||
sf = sensors_get_subfeature(name, feature,
|
||||
SENSORS_SUBFEATURE_FAN_INPUT);
|
||||
if (sf && get_input_value(name, sf, &val) == 0)
|
||||
{
|
||||
sprintf(tmp, "%s%4.0f RPM", ret, val);
|
||||
free(ret);
|
||||
strcpy(fan, tmp);
|
||||
return fan;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(ret);
|
||||
free(fan);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int get_label_size(const sensors_chip_name *name)
|
||||
{
|
||||
int i;
|
||||
const sensors_feature *iter;
|
||||
char *label;
|
||||
unsigned int max_size = 11; /* 11 as minimum label width */
|
||||
|
||||
i = 0;
|
||||
while ((iter = sensors_get_features(name, &i)))
|
||||
{
|
||||
if ((label = sensors_get_label(name, iter)) &&
|
||||
strlen(label) > max_size)
|
||||
max_size = strlen(label);
|
||||
free(label);
|
||||
}
|
||||
|
||||
/* One more for the colon, and one more to guarantee at least one
|
||||
space between that colon and the value */
|
||||
return max_size + 2;
|
||||
}
|
||||
|
||||
char** print_chip(const sensors_chip_name *name)
|
||||
{
|
||||
const sensors_feature *feature;
|
||||
int i, label_size;
|
||||
char *ret = NULL;
|
||||
char **fan = NULL;
|
||||
fan = realloc(fan, sizeof(char *) * 50);
|
||||
|
||||
label_size = get_label_size(name);
|
||||
|
||||
i = 0;
|
||||
int j = 0;
|
||||
while ((feature = sensors_get_features(name, &i)))
|
||||
{
|
||||
switch (feature->type)
|
||||
{
|
||||
case SENSORS_FEATURE_FAN:
|
||||
ret = print_chip_fan(name, feature, label_size);
|
||||
fan[j] = malloc(sizeof(char) * 20);
|
||||
if(!ret)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
strcpy(fan[j], ret);
|
||||
j++;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
fan[j] = NULL;
|
||||
return fan;
|
||||
}
|
||||
|
||||
char** kdk_fan_get_information()
|
||||
{
|
||||
int err;
|
||||
const char *config_file_name = NULL;
|
||||
FILE *config_file;
|
||||
|
||||
setlocale(LC_CTYPE, "");
|
||||
|
||||
if (config_file_name)
|
||||
{
|
||||
if (!strcmp(config_file_name, "-"))
|
||||
config_file = stdin;
|
||||
else
|
||||
config_file = fopen(config_file_name, "r");
|
||||
|
||||
if (!config_file)
|
||||
{
|
||||
perror(config_file_name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
config_file = NULL;
|
||||
}
|
||||
|
||||
err = sensors_init(config_file);
|
||||
if (err)
|
||||
{
|
||||
if (config_file)
|
||||
fclose(config_file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (config_file && fclose(config_file) == EOF)
|
||||
perror(config_file_name);
|
||||
|
||||
const sensors_chip_name *match = NULL;
|
||||
const sensors_chip_name *chip;
|
||||
int chip_nr;
|
||||
int cnt = 0;
|
||||
chip_nr = 0;
|
||||
int index = 0;
|
||||
char **fan = NULL;
|
||||
char **res = NULL;
|
||||
char **tmp = realloc(res, sizeof(char) * 50);
|
||||
if(!tmp)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
res = tmp;
|
||||
int j = 0;
|
||||
while ((chip = sensors_get_detected_chips(match, &chip_nr)))
|
||||
{
|
||||
int i = 0;
|
||||
fan = print_chip(chip);
|
||||
while(fan && fan[i])
|
||||
{
|
||||
res[i] = malloc(sizeof(char) * 32);
|
||||
if(!res[i])
|
||||
{
|
||||
free(tmp);
|
||||
goto err_out;
|
||||
}
|
||||
sprintf(res[i], "%s", fan[i]);
|
||||
i++;
|
||||
j = i;
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
res[j] = NULL;
|
||||
if(fan)
|
||||
{
|
||||
while (fan[index])
|
||||
{
|
||||
free(fan[index]);
|
||||
index ++;
|
||||
}
|
||||
free(fan);
|
||||
}
|
||||
return res;
|
||||
err_out:
|
||||
while (fan[index])
|
||||
{
|
||||
free(fan[index]);
|
||||
index ++;
|
||||
}
|
||||
free(fan);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline void kdk_fan_freeall(char **list)
|
||||
{
|
||||
if (! list)
|
||||
return;
|
||||
size_t index = 0;
|
||||
while (list[index])
|
||||
{
|
||||
free(list[index]);
|
||||
index ++;
|
||||
}
|
||||
free(list);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef LIBKYFAN_H
|
||||
#define LIBKYFAN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 获取风扇的信息
|
||||
*
|
||||
* @return char** 风扇的信息(名称,转速)
|
||||
*/
|
||||
extern char** kdk_fan_get_information();
|
||||
|
||||
/**
|
||||
* @brief 用于回收字符串列表
|
||||
*
|
||||
* @param ptr 字符串列表
|
||||
*/
|
||||
extern inline void kdk_fan_freeall(char **ptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,673 @@
|
|||
#include "libkyhw.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "hd.h"
|
||||
#include "glib.h"
|
||||
#include "pci/pci.h"
|
||||
#include "libkylog.h"
|
||||
#include "dbus/dbus-glib.h"
|
||||
|
||||
#define SERVERNAME "org.freedesktop.UPower"
|
||||
#define PROPERTIES_FACE "org.freedesktop.DBus.Properties"
|
||||
#define DEVICEINTERFACE "org.freedesktop.UPower.Device"
|
||||
|
||||
struct device
|
||||
{
|
||||
struct device *next;
|
||||
struct pci_dev *dev;
|
||||
/* Bus topology calculated by grow_tree() */
|
||||
struct device *bus_next;
|
||||
struct bus *parent_bus;
|
||||
struct bridge *bridge;
|
||||
/* Cache */
|
||||
unsigned int config_cached, config_bufsize;
|
||||
unsigned char *config; /* Cached configuration space data */
|
||||
unsigned char *present; /* Maps which configuration bytes are present */
|
||||
};
|
||||
|
||||
struct bridge
|
||||
{
|
||||
struct bridge *chain; /* Single-linked list of bridges */
|
||||
struct bridge *next, *child; /* Tree of bridges */
|
||||
struct bus *first_bus; /* List of buses connected to this bridge */
|
||||
unsigned int domain;
|
||||
unsigned int primary, secondary, subordinate; /* Bus numbers */
|
||||
struct device *br_dev;
|
||||
};
|
||||
|
||||
struct bus
|
||||
{
|
||||
unsigned int domain;
|
||||
unsigned int number;
|
||||
struct bus *sibling;
|
||||
struct bridge *parent_bridge;
|
||||
struct device *first_dev, **last_dev;
|
||||
};
|
||||
|
||||
struct hw_pci_dev
|
||||
{
|
||||
u_int16_t domain; /* PCI domain (host bridge) */
|
||||
u_int16_t bus; /* Higher byte can select host bridges */
|
||||
u_int8_t dev, func; /* Device and function */
|
||||
|
||||
u_int16_t vendor_id, device_id; /* Identity of the device */
|
||||
unsigned int irq; /* IRQ number */
|
||||
pciaddr_t base_addr[6]; /* Base addresses */
|
||||
pciaddr_t size[6]; /* Region sizes */
|
||||
pciaddr_t rom_base_addr; /* Expansion ROM base address */
|
||||
pciaddr_t rom_size; /* Expansion ROM size */
|
||||
|
||||
u_int8_t config[256]; /* non-root users can only use first 64 bytes */
|
||||
};
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
*
|
||||
* kysdk interface functions
|
||||
*
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
*/
|
||||
|
||||
bool scan_pci_legacy(struct hw_pci_dev *d, hd_t *hd)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
f = fopen("/proc/bus/pci/devices", "r");
|
||||
if (f)
|
||||
{
|
||||
char buf[512];
|
||||
|
||||
while (fgets(buf, sizeof(buf) - 1, f))
|
||||
{
|
||||
unsigned int dfn, vend, cnt;
|
||||
char driver[50];
|
||||
memset(driver, 0, sizeof(driver));
|
||||
cnt = sscanf(buf,
|
||||
"%x %x %x %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx %[ -z]s",
|
||||
&dfn,
|
||||
&vend,
|
||||
&d->irq,
|
||||
&d->base_addr[0],
|
||||
&d->base_addr[1],
|
||||
&d->base_addr[2],
|
||||
&d->base_addr[3],
|
||||
&d->base_addr[4],
|
||||
&d->base_addr[5],
|
||||
&d->rom_base_addr,
|
||||
&d->size[0],
|
||||
&d->size[1],
|
||||
&d->size[2],
|
||||
&d->size[3], &d->size[4], &d->size[5], &d->rom_size, driver);
|
||||
|
||||
if (cnt != 9 && cnt != 10 && cnt != 17 && cnt != 18)
|
||||
break;
|
||||
|
||||
d->bus = dfn >> 8;
|
||||
d->dev = PCI_SLOT(dfn & 0xff);
|
||||
d->func = PCI_FUNC(dfn & 0xff);
|
||||
d->vendor_id = vend >> 16;
|
||||
d->device_id = vend & 0xffff;
|
||||
|
||||
if ((d->vendor_id != (uint16_t)(hd->vendor.id)) || (d->device_id != (uint16_t)(hd->device.id)))
|
||||
continue;
|
||||
|
||||
int fd = -1;
|
||||
char device_path[512];
|
||||
sprintf(device_path, "/proc/bus/pci/%02x/%02x.%x", d->bus, d->dev, d->func);
|
||||
fd = open(device_path, O_RDONLY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
if (-1 == read(fd, d->config, sizeof(d->config)))
|
||||
memset(d->config, 0, sizeof(d->config));
|
||||
close(fd);
|
||||
}
|
||||
break;
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct HWInfo *kdk_hw_get_hwinfo(int type)
|
||||
{
|
||||
struct HWInfo *result = NULL;
|
||||
|
||||
hd_data_t *hd_data;
|
||||
hd_data = (hd_data_t *)calloc(1, sizeof *hd_data);
|
||||
if (!hd_data)
|
||||
{
|
||||
klog_err("%s 申请内存失败于%s", "kdk_hw_get_sound", "hd_data");
|
||||
goto out;
|
||||
}
|
||||
|
||||
hd_data->progress = NULL;
|
||||
hd_data->debug = ~(HD_DEB_DRIVER_INFO | HD_DEB_HDDB);
|
||||
|
||||
hd_t *hd, *hd0;
|
||||
hd0 = hd_list(hd_data, type, 1, NULL);
|
||||
for (hd = hd0; hd; hd = hd->next)
|
||||
{
|
||||
|
||||
struct HWInfo *node = (struct HWInfo *)calloc(1, sizeof *node);
|
||||
if (!node)
|
||||
{
|
||||
klog_err("%s 申请内存失败于%s", "kdk_hw_get_sound", "struct HWInfo");
|
||||
kdk_hw_free_hw(result);
|
||||
result = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
int isCamera = 0;
|
||||
if(hd->model && strstr(hd->model, "camera") )
|
||||
isCamera = 1;
|
||||
else if(hd->model && strstr(hd->model, "Camera") )
|
||||
isCamera = 1;
|
||||
else if(hd->model && strstr(hd->model, "webcam") )
|
||||
isCamera = 1;
|
||||
else if(hd->device.name && strstr(hd->device.name, "camera"))
|
||||
isCamera = 1;
|
||||
else if(hd->device.name && strstr(hd->device.name, "Camera"))
|
||||
isCamera = 1;
|
||||
else if(hd->driver && strstr(hd->driver, "uvcvideo") )
|
||||
isCamera = 1;
|
||||
|
||||
if ((hw_usb == type) && !isCamera)
|
||||
{
|
||||
free(node);
|
||||
continue;
|
||||
}
|
||||
strcpy(node->model, hd->model ? hd->model : "none");
|
||||
strcpy(node->vendor, hd->vendor.name ? hd->vendor.name : "none");
|
||||
strcpy(node->device, hd->device.name ? hd->device.name : "none");
|
||||
strcpy(node->driver, hd->driver ? hd->driver : "none");
|
||||
strcpy(node->revision, hd->revision.name ? hd->revision.name : "none");
|
||||
if(0 == strcmp(node->revision,"none"))
|
||||
sprintf(node->revision, "0x%x", hd->revision.id);
|
||||
strcpy(node->busid, hd->bus.name ? hd->bus.name : "none");
|
||||
|
||||
if (hw_sound == type)
|
||||
{
|
||||
struct hw_pci_dev d;
|
||||
scan_pci_legacy(&d, hd);
|
||||
u_int16_t status = d.config[PCI_STATUS] | (d.config[PCI_STATUS + 1] << 8);
|
||||
if (status & PCI_STATUS_66MHZ)
|
||||
strcpy(node->clock, "66 MHZ"); // 66MHz
|
||||
else
|
||||
strcpy(node->clock, "33 MHZ"); // 33MHz
|
||||
|
||||
strcpy(node->width, "32 bits");
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
int p = PCI_BASE_ADDRESS_0 + 4 * i;
|
||||
|
||||
u_int32_t flg = d.config[p] | (d.config[p + 1] << 8) |
|
||||
(d.config[p + 2] << 16) | (d.config[p + 3] << 24);
|
||||
u_int32_t pos = d.base_addr[i];
|
||||
u_int32_t len = d.size[i];
|
||||
|
||||
if (flg == 0xffffffff)
|
||||
flg = 0;
|
||||
|
||||
if (!pos && !flg && !len)
|
||||
continue;
|
||||
|
||||
if (pos && !flg) /* Reported by the OS, but not by the device */
|
||||
{
|
||||
flg = pos;
|
||||
}
|
||||
|
||||
int t = flg & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
|
||||
if (t == PCI_BASE_ADDRESS_MEM_TYPE_64)
|
||||
{
|
||||
strcpy(node->width, "64 bits");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(node->width, "none");
|
||||
strcpy(node->clock, "none");
|
||||
}
|
||||
|
||||
hd_dev_num_t *d = &hd->unix_dev_num;
|
||||
if (d->type)
|
||||
{
|
||||
sprintf(node->devicenum, "%s %u:%u",
|
||||
d->type == 'b' ? "block" : "char",
|
||||
d->major, d->minor);
|
||||
if (d->range > 1)
|
||||
{
|
||||
sprintf(node->devicenum, "-%u:%u",
|
||||
d->major, d->minor + d->range - 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(node->devicenum, "%s", "none");
|
||||
}
|
||||
node->next = result;
|
||||
result = node;
|
||||
}
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
void kdk_hw_free_hw(struct HWInfo *list)
|
||||
{
|
||||
struct HWInfo *tmp = NULL;
|
||||
while (list)
|
||||
{
|
||||
tmp = list;
|
||||
list = list->next;
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static void _write_info(struct power_device *node, GHashTable *info_hash)
|
||||
{
|
||||
GValue *attr = (GValue *)g_hash_table_lookup(info_hash, "NativePath");
|
||||
strcpy(node->native_path, attr ? g_value_get_string(attr) : "None");
|
||||
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "PowerSupply");
|
||||
node->power_supply = attr ? g_value_get_boolean(attr) : false;
|
||||
|
||||
struct tm *time_tm;
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "UpdateTime");
|
||||
time_t t = (time_t)g_value_get_uint64(attr);
|
||||
time_tm = localtime(&t);
|
||||
strftime(node->updated, sizeof node->updated, "%c", time_tm);
|
||||
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "HasHistory");
|
||||
node->has_history = attr ? g_value_get_boolean(attr) : false;
|
||||
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "HasStatistics");
|
||||
node->has_statistics = attr ? g_value_get_boolean(attr) : false;
|
||||
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "IsPersent");
|
||||
node->is_persent = attr ? g_value_get_boolean(attr) : false;
|
||||
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "IsRechargeable");
|
||||
node->is_rechargeable = attr ? g_value_get_boolean(attr) : false;
|
||||
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "State");
|
||||
switch (g_value_get_uint(attr))
|
||||
{
|
||||
case 1:
|
||||
strcpy(node->technology, "charging");
|
||||
break;
|
||||
case 2:
|
||||
strcpy(node->technology, "discharging");
|
||||
break;
|
||||
case 3:
|
||||
strcpy(node->technology, "empty");
|
||||
break;
|
||||
case 4:
|
||||
strcpy(node->technology, "fully-charged");
|
||||
break;
|
||||
case 5:
|
||||
strcpy(node->technology, "pending-charge");
|
||||
break;
|
||||
case 6:
|
||||
strcpy(node->technology, "pending-discharge");
|
||||
break;
|
||||
default:
|
||||
strcpy(node->technology, "unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "WarningLevel");
|
||||
switch (g_value_get_uint(attr))
|
||||
{
|
||||
case 1:
|
||||
strcpy(node->technology, "none");
|
||||
break;
|
||||
case 2:
|
||||
strcpy(node->technology, "discharging");
|
||||
break;
|
||||
case 3:
|
||||
strcpy(node->technology, "low");
|
||||
break;
|
||||
case 4:
|
||||
strcpy(node->technology, "critical");
|
||||
break;
|
||||
case 5:
|
||||
strcpy(node->technology, "action");
|
||||
break;
|
||||
case 6:
|
||||
strcpy(node->technology, "normal");
|
||||
break;
|
||||
case 7:
|
||||
strcpy(node->technology, "high");
|
||||
break;
|
||||
case 8:
|
||||
strcpy(node->technology, "full");
|
||||
break;
|
||||
default:
|
||||
strcpy(node->technology, "unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "Energy");
|
||||
node->energy = attr ? g_value_get_double(attr) : 0.0f;
|
||||
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "EnergyEmpty");
|
||||
node->energy_empty = attr ? g_value_get_double(attr) : 0.0f;
|
||||
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "EnergyFull");
|
||||
node->energy_full = attr ? g_value_get_double(attr) : 0.0f;
|
||||
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "EnergyFullDesign");
|
||||
node->energy_full_design = attr ? g_value_get_double(attr) : 0.0f;
|
||||
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "EnergyRate");
|
||||
node->energy_rate = attr ? g_value_get_double(attr) : 0.0f;
|
||||
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "Voltage");
|
||||
node->voltage = attr ? g_value_get_double(attr) : 0.0f;
|
||||
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "TimeToEmpty");
|
||||
node->time_to_empty = attr ? g_value_get_int64(attr) : 0.0f;
|
||||
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "TimeToFull");
|
||||
node->time_to_full = attr ? g_value_get_int64(attr) : 0.0f;
|
||||
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "Percentage");
|
||||
node->time_to_full = attr ? g_value_get_double(attr) : 0.0f;
|
||||
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "Temperature");
|
||||
node->time_to_full = attr ? g_value_get_double(attr) : 0.0f;
|
||||
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "Capacity");
|
||||
node->time_to_full = attr ? g_value_get_double(attr) : 0.0f;
|
||||
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "Technology");
|
||||
switch (g_value_get_uint(attr))
|
||||
{
|
||||
case 1:
|
||||
strcpy(node->technology, "lithium-ion");
|
||||
break;
|
||||
case 2:
|
||||
strcpy(node->technology, "lithium-polymer");
|
||||
break;
|
||||
case 3:
|
||||
strcpy(node->technology, "lithium-iron-phosphate");
|
||||
break;
|
||||
case 4:
|
||||
strcpy(node->technology, "lead-acid");
|
||||
break;
|
||||
case 5:
|
||||
strcpy(node->technology, "nickel-cadmium");
|
||||
break;
|
||||
case 6:
|
||||
strcpy(node->technology, "nickel-metal-hydride");
|
||||
break;
|
||||
default:
|
||||
strcpy(node->technology, "unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "Online");
|
||||
node->online = attr ? g_value_get_boolean(attr) : false;
|
||||
|
||||
attr = (GValue *)g_hash_table_lookup(info_hash, "IconName");
|
||||
strcpy(node->icon_name, attr ? g_value_get_string(attr) : "None");
|
||||
}
|
||||
|
||||
static void _daemon_forech(gpointer key, gpointer value, gpointer user_data)
|
||||
{
|
||||
char *tmp = (char *)key;
|
||||
GValue *data = (GValue *)value;
|
||||
struct Power *result = (struct Power *)user_data;
|
||||
if (0 == strcmp(tmp, "DaemonVersion"))
|
||||
strcpy(result->daemon_version, g_value_get_string(data));
|
||||
if (0 == strcmp(tmp, "LidIsClosed"))
|
||||
result->lid_is_closed = g_value_get_boolean(data);
|
||||
if (0 == strcmp(tmp, "LidIsPresent"))
|
||||
result->lid_is_closed = g_value_get_boolean(data);
|
||||
if (0 == strcmp(tmp, "OnBattery"))
|
||||
result->lid_is_closed = g_value_get_boolean(data);
|
||||
}
|
||||
|
||||
static bool get_daemon_info(DBusGConnection *bus, GError **error, struct Power *result, DBusGProxy **upower_proxy)
|
||||
{
|
||||
bool success = true;
|
||||
char *critical_action = NULL;
|
||||
DBusGProxy *properties_porxy = NULL;
|
||||
GHashTable *info_hash = NULL;
|
||||
|
||||
do
|
||||
{
|
||||
properties_porxy = dbus_g_proxy_new_for_name(bus,
|
||||
SERVERNAME, // server
|
||||
"/org/freedesktop/UPower", // path
|
||||
PROPERTIES_FACE); // interface
|
||||
|
||||
if (!dbus_g_proxy_call(properties_porxy, "GetAll", error,
|
||||
G_TYPE_STRING, SERVERNAME,
|
||||
G_TYPE_INVALID,
|
||||
dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), &info_hash,
|
||||
G_TYPE_INVALID))
|
||||
{
|
||||
klog_err("Failed to call GetAll in path %s : %s\n", "/org/freedesktop/UPower", (*error)->message);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// 轮询哈希表
|
||||
g_hash_table_foreach(info_hash, _daemon_forech, result);
|
||||
|
||||
// 创建UPower代理
|
||||
*upower_proxy = dbus_g_proxy_new_for_name(bus,
|
||||
SERVERNAME, // server
|
||||
"/org/freedesktop/UPower", // path
|
||||
SERVERNAME); // interface
|
||||
// 获取CriticalAction
|
||||
if (!dbus_g_proxy_call(*upower_proxy, "GetCriticalAction", error,
|
||||
G_TYPE_INVALID,
|
||||
G_TYPE_STRING, &critical_action,
|
||||
G_TYPE_INVALID))
|
||||
{
|
||||
klog_err("Failed to call GetCriticalAction in path %s : %s\n", "/org/freedesktop/UPower", (*error)->message);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
strcpy(result->critical_action, critical_action);
|
||||
} while (0);
|
||||
|
||||
if (properties_porxy)
|
||||
g_object_unref((properties_porxy));
|
||||
if (info_hash)
|
||||
g_hash_table_unref(info_hash);
|
||||
if (critical_action)
|
||||
free(critical_action);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool get_display_info(DBusGConnection *bus, DBusGProxy *upower_proxy, GError **error, struct Power *result)
|
||||
{
|
||||
bool success = true;
|
||||
DBusGProxy *display_proxy = NULL;
|
||||
GHashTable *info_hash = NULL;
|
||||
char *display_path = NULL;
|
||||
|
||||
// 获取displaydevice
|
||||
do
|
||||
{
|
||||
if (!dbus_g_proxy_call(upower_proxy, "GetDisplayDevice", error,
|
||||
G_TYPE_INVALID,
|
||||
DBUS_TYPE_G_OBJECT_PATH, &display_path,
|
||||
G_TYPE_INVALID))
|
||||
{
|
||||
klog_err("Failed to call GetDisplayDevice in path %s : %s\n",
|
||||
"/org/freedesktop/UPower",
|
||||
(*error)->message);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
display_proxy = dbus_g_proxy_new_for_name(bus,
|
||||
SERVERNAME, // server
|
||||
display_path, // path
|
||||
PROPERTIES_FACE); // interface
|
||||
if (!dbus_g_proxy_call(display_proxy, "GetAll", error,
|
||||
G_TYPE_STRING, DEVICEINTERFACE,
|
||||
G_TYPE_INVALID,
|
||||
dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), &info_hash,
|
||||
G_TYPE_INVALID))
|
||||
{
|
||||
klog_err("Failed to call GetAll in path %s : %s\n", display_path, (*error)->message);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
struct power_device *node = (struct power_device *)calloc(1, sizeof *node);
|
||||
if (!node)
|
||||
{
|
||||
klog_err("Failed to request memory %s\n", display_path);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// 写入display device数据
|
||||
result->devices = node;
|
||||
strcpy(node->name, display_path);
|
||||
_write_info(node, info_hash);
|
||||
|
||||
} while (0);
|
||||
|
||||
if (display_proxy)
|
||||
g_object_unref(display_proxy);
|
||||
if (display_path)
|
||||
free(display_path);
|
||||
if (info_hash)
|
||||
g_hash_table_unref(info_hash);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool get_device_info(DBusGConnection *bus, GError **error, const char *p, struct Power *result)
|
||||
{
|
||||
bool success = true;
|
||||
DBusGProxy *device_proxy = NULL;
|
||||
GHashTable *info_hash;
|
||||
do
|
||||
{
|
||||
device_proxy = dbus_g_proxy_new_for_name(bus,
|
||||
SERVERNAME, // server
|
||||
p, // path
|
||||
PROPERTIES_FACE); // interface
|
||||
if (!dbus_g_proxy_call(device_proxy, "GetAll", error,
|
||||
G_TYPE_STRING, DEVICEINTERFACE,
|
||||
G_TYPE_INVALID,
|
||||
dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), &info_hash,
|
||||
G_TYPE_INVALID))
|
||||
{
|
||||
klog_err("Failed to call GetAll in path %s : %s\n", p, (*error)->message);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
struct power_device *node = (struct power_device *)calloc(1, sizeof *node);
|
||||
if (!node)
|
||||
{
|
||||
klog_err("Failed to request memory %s\n", p);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
// 前插
|
||||
node->next = result->devices;
|
||||
result->devices = node;
|
||||
|
||||
// 写入device device数据
|
||||
strcpy(node->name, p);
|
||||
_write_info(node, info_hash);
|
||||
} while (0);
|
||||
|
||||
if (device_proxy)
|
||||
g_object_unref(device_proxy);
|
||||
if (info_hash)
|
||||
g_hash_table_unref(info_hash);
|
||||
return success;
|
||||
}
|
||||
|
||||
struct Power *kdk_hw_get_powerinfo()
|
||||
{
|
||||
bool success = true;
|
||||
DBusGProxy *upower_proxy = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
DBusGConnection *bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
|
||||
if (!bus)
|
||||
{
|
||||
klog_err("Couldn't connect to system bus : %s\n", error->message);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct Power *result = (struct Power *)calloc(1, sizeof *result);
|
||||
if (!result)
|
||||
{
|
||||
klog_err("Failed to request memory Power");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(success = get_daemon_info(bus, &error, result, &upower_proxy)))
|
||||
goto out;
|
||||
|
||||
if (!(success = get_display_info(bus, upower_proxy, &error, result)))
|
||||
goto out;
|
||||
|
||||
// 获取Device列表
|
||||
GPtrArray *devices = NULL;
|
||||
if (!dbus_g_proxy_call(upower_proxy, "EnumerateDevices", &error,
|
||||
G_TYPE_INVALID,
|
||||
dbus_g_type_get_collection("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), &devices,
|
||||
G_TYPE_INVALID))
|
||||
{
|
||||
klog_err("Failed to call EnumerateDevices in path %s : %s\n", "/org/freedesktop/UPower", error->message);
|
||||
success = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (guint i = 0; i < devices->len; i++)
|
||||
{
|
||||
if (!(success = get_device_info(bus, &error, (char *)g_ptr_array_index(devices, i), result)))
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (!success)
|
||||
{
|
||||
kdk_hw_free_power_info(result);
|
||||
result = NULL;
|
||||
}
|
||||
if (error)
|
||||
g_error_free(error);
|
||||
if (devices)
|
||||
g_ptr_array_unref(devices);
|
||||
if (upower_proxy)
|
||||
g_object_unref(upower_proxy);
|
||||
if (bus)
|
||||
dbus_g_connection_unref(bus);
|
||||
return result;
|
||||
}
|
||||
|
||||
void kdk_hw_free_power_info(struct Power *info)
|
||||
{
|
||||
if (info)
|
||||
{
|
||||
struct power_device *tmp = NULL;
|
||||
while (info->devices)
|
||||
{
|
||||
tmp = info->devices;
|
||||
info->devices = info->devices->next;
|
||||
free(tmp);
|
||||
}
|
||||
free(info);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
#ifndef KDK_SYSTEM_HW_ASSISTANT_H
|
||||
#define KDK_SYSTEM_HW_ASSISTANT_H
|
||||
#define ATTRSIZE 128
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
*
|
||||
* libkyassistant data structures
|
||||
*
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
*/
|
||||
|
||||
struct HWInfo
|
||||
{
|
||||
char model[ATTRSIZE];
|
||||
char vendor[ATTRSIZE];
|
||||
char device[ATTRSIZE];
|
||||
char driver[ATTRSIZE];
|
||||
char revision[ATTRSIZE];
|
||||
char busid[ATTRSIZE];
|
||||
char devicenum[ATTRSIZE];
|
||||
char width[8];
|
||||
char clock[8];
|
||||
struct HWInfo *next;
|
||||
};
|
||||
|
||||
struct power_device
|
||||
{
|
||||
char name[256];
|
||||
char native_path[32];
|
||||
bool power_supply;
|
||||
char updated[64];
|
||||
bool has_history;
|
||||
bool has_statistics;
|
||||
bool is_persent;
|
||||
bool is_rechargeable;
|
||||
char state[32];
|
||||
char warning_level[32];
|
||||
double energy;
|
||||
double energy_empty;
|
||||
double energy_full;
|
||||
double energy_full_design;
|
||||
double energy_rate;
|
||||
double voltage;
|
||||
long time_to_empty;
|
||||
long time_to_full;
|
||||
double percentage;
|
||||
double temperature;
|
||||
double capacity;
|
||||
char technology[32];
|
||||
bool online;
|
||||
char icon_name[64];
|
||||
struct power_device *next;
|
||||
};
|
||||
|
||||
struct Power
|
||||
{
|
||||
char daemon_version[32];
|
||||
bool on_battery;
|
||||
bool lid_is_closed;
|
||||
bool lid_is_present;
|
||||
char critical_action[32];
|
||||
struct power_device *devices;
|
||||
};
|
||||
|
||||
struct KPci
|
||||
{
|
||||
char slot_path[16];
|
||||
char class_name[128];
|
||||
char product_name[128];
|
||||
unsigned char rev;
|
||||
char ss_name[256];
|
||||
char driver_use[1024];
|
||||
char **modules;
|
||||
int module_count;
|
||||
struct KPci *next;
|
||||
};
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
*
|
||||
* libkyassistant interface function
|
||||
*
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief 获取硬件信息
|
||||
* @arg type 3 keyboard; 5 mouse; 15 sound; 23 cdrom; 27 usb
|
||||
* @return 硬件信息,具体参考返回结构体
|
||||
*/
|
||||
extern struct HWInfo *kdk_hw_get_hwinfo(int type);
|
||||
extern void kdk_hw_free_hw(struct HWInfo *list);
|
||||
|
||||
/**
|
||||
* @brief 获取电源信息
|
||||
* @return 电源信息,具体参考返回结构体
|
||||
*/
|
||||
extern struct Power *kdk_hw_get_powerinfo();
|
||||
extern void kdk_hw_free_power_info(struct Power *info);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // KDK_SYSTEM_HW_ASSISTANT_H
|
|
@ -6,7 +6,7 @@
|
|||
#include <libkylog.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sdkmarcos.h>
|
||||
#include <kysdk/kysdk-base/sdkmarcos.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/if.h>
|
||||
|
@ -18,6 +18,8 @@
|
|||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <glib.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/ethtool.h>
|
||||
|
||||
enum cardspec{
|
||||
NCSPEC_ALL,
|
||||
|
@ -84,6 +86,7 @@ get_ip_list(enum cardcfg type,const char *nc)
|
|||
int count = 0;
|
||||
char curAddr[64] = "\0";
|
||||
char **result = NULL;
|
||||
char **res = NULL;
|
||||
DIR *dir = NULL;
|
||||
struct dirent *file;
|
||||
char *path = "/etc/NetworkManager/system-connections/";
|
||||
|
@ -151,9 +154,10 @@ get_ip_list(enum cardcfg type,const char *nc)
|
|||
val->str[i] = '\0';
|
||||
if (0 != strcmp(curAddr, val->str))
|
||||
{
|
||||
result = (char **)realloc(result, (++count + 1) * sizeof(char *));
|
||||
if(!result)
|
||||
res = (char **)realloc(result, (++count + 1) * sizeof(char *));
|
||||
if(!res)
|
||||
goto err_out;
|
||||
result = res;
|
||||
result[count - 1] = (char *)calloc(i + 1, sizeof(char));
|
||||
if(!result[count - 1])
|
||||
goto err_out;
|
||||
|
@ -484,7 +488,7 @@ int kdk_nc_is_wireless(const char *nc)
|
|||
char buffer[2 * IFNAMSIZ + 1];
|
||||
int fd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
goto out;
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
strncpy(buffer, nc, sizeof(buffer));
|
||||
ret = ioctl(fd, SIOCGIWNAME, &buffer) == 0 ? 1 : 0;
|
||||
|
@ -640,6 +644,26 @@ int kdk_nc_get_vendor_and_product(const char *nc, char *vendor, char *product)
|
|||
return 0;
|
||||
}
|
||||
|
||||
char *kdk_nc_get_driver(const char *nc)
|
||||
{
|
||||
int ret;
|
||||
struct ifreq ifr;
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
struct ethtool_drvinfo *driverInfo = (struct ethtool_drvinfo *)calloc(1, sizeof(struct ethtool_drvinfo));
|
||||
driverInfo->cmd = ETHTOOL_GDRVINFO;
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strcpy(ifr.ifr_name, nc);
|
||||
ifr.ifr_data = (char *)driverInfo;
|
||||
ret = ioctl(fd, SIOCETHTOOL, &ifr);
|
||||
if (0 != ret)
|
||||
return NULL;
|
||||
char *driver = (char*)malloc(32);
|
||||
strcpy(driver,driverInfo->driver);
|
||||
free(driverInfo);
|
||||
return driver;
|
||||
}
|
||||
|
||||
inline void kdk_nc_freeall(char **list)
|
||||
{
|
||||
if (! list)
|
||||
|
|
|
@ -72,24 +72,6 @@ extern char** kdk_nc_get_ipv4(const char* nc);
|
|||
*/
|
||||
extern char* kdk_nc_get_private_ipv6(const char *nc);
|
||||
|
||||
/**
|
||||
* @brief 获取指定网卡的有线/无线类型
|
||||
*
|
||||
* @param nc 网卡名称,如eno1
|
||||
* @return int 0 有线 1 无线
|
||||
*/
|
||||
extern int kdk_nc_is_wireless(const char *nc);
|
||||
|
||||
/**
|
||||
* @brief 获取指定网卡的厂商名称和设备型号
|
||||
*
|
||||
* @param nc 网卡名称,如eno1
|
||||
* @param vendor 网卡制造厂商,出参,需要提前分配好空足够空间
|
||||
* @param porduct 网卡型号,出参,需要提前分配好空足够空间
|
||||
* @return int 成功返回 0 失败返回 -1
|
||||
*/
|
||||
extern int kdk_nc_get_vendor_and_product(const char *nc, char *vendor, char *product);
|
||||
|
||||
/**
|
||||
* @brief 获取指定网卡的所有IPv6地址
|
||||
*
|
||||
|
@ -116,6 +98,14 @@ extern int kdk_nc_is_wireless(const char *nc);
|
|||
*/
|
||||
extern int kdk_nc_get_vendor_and_product(const char *nc, char *vendor, char *product);
|
||||
|
||||
/**
|
||||
* @brief 获取指定网卡的驱动
|
||||
*
|
||||
* @param nc 网卡名称,如eno1
|
||||
* @return char * 网卡驱动
|
||||
*/
|
||||
extern char *kdk_nc_get_driver(const char *nc);
|
||||
|
||||
/**
|
||||
* @brief 用于回收字符串列表
|
||||
*
|
||||
|
|
|
@ -22,7 +22,7 @@ int num_options; // cups设置
|
|||
|
||||
char **kdk_printer_get_list()
|
||||
{
|
||||
printf("[%s] Start\n", __FUNCTION__);
|
||||
// printf("[%s] Start\n", __FUNCTION__);
|
||||
cups_dest_t *dests = NULL;
|
||||
int num_dests = 0;
|
||||
int i = 0;
|
||||
|
@ -40,22 +40,42 @@ char **kdk_printer_get_list()
|
|||
}
|
||||
for (i = 0; i < num_dests; i++)
|
||||
{
|
||||
printf("[%s] printer name is %s \n", __FUNCTION__, dests[i].name);
|
||||
// printf("[%s] printer name is %s \n", __FUNCTION__, dests[i].name);
|
||||
char **tmp = realloc(printers, sizeof(char *) * i);
|
||||
if(!tmp)
|
||||
{
|
||||
goto err_out;
|
||||
}
|
||||
printers = tmp;
|
||||
printers[i] = malloc(sizeof(char) * (strlen(dests[i].name) + 1));
|
||||
if(!printers[i])
|
||||
{
|
||||
goto err_out;
|
||||
}
|
||||
strcpy(printers[i], dests[i].name);
|
||||
}
|
||||
char **tmp = realloc(printers, sizeof(char *) * (i + 1));
|
||||
if(!tmp)
|
||||
{
|
||||
goto err_out;
|
||||
}
|
||||
printers = tmp;
|
||||
printers[i] = NULL;
|
||||
cupsFreeDests(num_dests, dests);
|
||||
return printers;
|
||||
err_out:
|
||||
while (i)
|
||||
{
|
||||
free(printers[i - 1]);
|
||||
i--;
|
||||
}
|
||||
free(printers);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char **kdk_printer_get_available_list()
|
||||
{
|
||||
printf("[%s] Start\n", __FUNCTION__);
|
||||
// printf("[%s] Start\n", __FUNCTION__);
|
||||
cups_dest_t *dests = NULL;
|
||||
int num_dests = 0;
|
||||
int i = 0, j = 0;
|
||||
|
@ -75,34 +95,54 @@ char **kdk_printer_get_available_list()
|
|||
{
|
||||
if (kdk_printer_get_status(dests[i].name) == CUPS_PRINTER_STATE_IDLE)
|
||||
{
|
||||
printf("[%s] printer name is %s \n", __FUNCTION__, dests[i].name);
|
||||
// printf("[%s] printer name is %s \n", __FUNCTION__, dests[i].name);
|
||||
char **tmp = realloc(printers, sizeof(char *) * j);
|
||||
if(!tmp)
|
||||
{
|
||||
goto err_out;
|
||||
}
|
||||
printers = tmp;
|
||||
printers[j] = malloc(sizeof(char) * (strlen(dests[i].name) + 1));
|
||||
if(!printers[j])
|
||||
{
|
||||
goto err_out;
|
||||
}
|
||||
strcpy(printers[j], dests[i].name);
|
||||
//
|
||||
j++;
|
||||
}
|
||||
}
|
||||
char **tmp = realloc(printers, sizeof(char *) * (j + 1));
|
||||
if(!tmp)
|
||||
{
|
||||
goto err_out;
|
||||
}
|
||||
printers = tmp;
|
||||
printers[j] = NULL;
|
||||
|
||||
cupsFreeDests(num_dests, dests);
|
||||
|
||||
return printers;
|
||||
err_out:
|
||||
while (j)
|
||||
{
|
||||
free(printers[j]);
|
||||
j--;
|
||||
}
|
||||
free(printers);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int kdk_printer_remove_options()
|
||||
{
|
||||
printf("[%s] Start\n", __FUNCTION__);
|
||||
// printf("[%s] Start\n", __FUNCTION__);
|
||||
if (num_options != 0 && cups_options != NULL)
|
||||
{
|
||||
cupsFreeOptions(num_options, cups_options);
|
||||
num_options = 0;
|
||||
cups_options = NULL;
|
||||
}
|
||||
printf("[%s] num_options = %d\n", __FUNCTION__, num_options);
|
||||
// printf("[%s] num_options = %d\n", __FUNCTION__, num_options);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -110,7 +150,7 @@ void kdk_printer_set_options(int number_up,
|
|||
const char *media,
|
||||
const char *number_up_layout, const char *sides)
|
||||
{
|
||||
printf("[%s] Start\n", __FUNCTION__);
|
||||
// printf("[%s] Start\n", __FUNCTION__);
|
||||
kdk_printer_remove_options();
|
||||
cups_options = NULL;
|
||||
num_options = 0;
|
||||
|
@ -130,10 +170,10 @@ void kdk_printer_set_options(int number_up,
|
|||
|
||||
int kdk_printer_print_local_file(const char *printername, const char *filepath)
|
||||
{
|
||||
printf("[%s] Start\n", __FUNCTION__);
|
||||
printf("[%s] printer_name: %s, file_path: %s\n", __FUNCTION__,
|
||||
printername,
|
||||
filepath);
|
||||
// printf("[%s] Start\n", __FUNCTION__);
|
||||
// printf("[%s] printer_name: %s, file_path: %s\n", __FUNCTION__,
|
||||
// printername,
|
||||
// filepath);
|
||||
int jobid = 0;
|
||||
// stop状态禁止打印
|
||||
if (kdk_printer_get_status(printername) != CUPS_PRINTER_STATE_STOPPED)
|
||||
|
@ -148,11 +188,11 @@ int kdk_printer_print_local_file(const char *printername, const char *filepath)
|
|||
|
||||
int kdk_printer_cancel_all_jobs(const char *printername)
|
||||
{
|
||||
printf("[%s] Start\n", __FUNCTION__);
|
||||
// printf("[%s] Start\n", __FUNCTION__);
|
||||
int ret = cupsCancelJob(printername, CUPS_JOBID_ALL); // 1=success 0=fail
|
||||
if (ret == 0)
|
||||
{
|
||||
printf("%s ,job_id = CUPS_JOBID_ALL, find err = %s ", __FUNCTION__, cupsLastErrorString());
|
||||
// printf("%s ,job_id = CUPS_JOBID_ALL, find err = %s ", __FUNCTION__, cupsLastErrorString());
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -216,7 +256,7 @@ _show_printer_state(const char *printers /* I - Destinations */
|
|||
"printer-state"};
|
||||
|
||||
#ifdef PRT_DEBUG
|
||||
printf(("show_devices(printers=\"%s\")\n", printers));
|
||||
// printf(("show_devices(printers=\"%s\")\n", printers));
|
||||
#endif
|
||||
if (printers != NULL && !strcmp(printers, "all"))
|
||||
printers = NULL;
|
||||
|
@ -356,7 +396,7 @@ _show_printer_state(const char *printers /* I - Destinations */
|
|||
|
||||
int kdk_printer_get_status(const char *printername)
|
||||
{
|
||||
printf("[%s] Start\n", __FUNCTION__);
|
||||
// printf("[%s] Start\n", __FUNCTION__);
|
||||
http_t *http; /* Connection to server */
|
||||
int ret;
|
||||
if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
|
||||
|
@ -384,7 +424,7 @@ size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream)
|
|||
//获取url内的文件名
|
||||
char* kdk_printer_get_filename(const char *url)
|
||||
{
|
||||
printf("[%s] Start\n", __FUNCTION__);
|
||||
// printf("[%s] Start\n", __FUNCTION__);
|
||||
char *filename = malloc(strlen(url) + 1);
|
||||
memset(filename, 0, sizeof(url));
|
||||
int len = strlen(url);
|
||||
|
@ -402,7 +442,7 @@ char* kdk_printer_get_filename(const char *url)
|
|||
//检查url是否存在
|
||||
int check_url(char *url)
|
||||
{
|
||||
printf("[%s] Start\n", __FUNCTION__);
|
||||
// printf("[%s] Start\n", __FUNCTION__);
|
||||
// 获得一个CURL会话,进行网络操作
|
||||
CURL *handle = curl_easy_init();
|
||||
if (NULL != handle && NULL != url)
|
||||
|
@ -445,15 +485,15 @@ int check_url(char *url)
|
|||
// 下载url到文件
|
||||
int download_file(char *url, const char *savefile)
|
||||
{
|
||||
printf("[%s] Start\n", __FUNCTION__);
|
||||
// printf("[%s] Start\n", __FUNCTION__);
|
||||
CURL *curl;
|
||||
FILE *fp = NULL;
|
||||
CURLcode res;
|
||||
printf("[%s] url = %s \n", __FUNCTION__, url);
|
||||
printf("[%s] savefile = %s \n", __FUNCTION__, savefile);
|
||||
// printf("[%s] url = %s \n", __FUNCTION__, url);
|
||||
// printf("[%s] savefile = %s \n", __FUNCTION__, savefile);
|
||||
//检查保存路径是否可用
|
||||
fp = fopen(savefile, "wb");
|
||||
printf("[%s] fp = %d \n", __FUNCTION__, fp);
|
||||
// printf("[%s] fp = %d \n", __FUNCTION__, fp);
|
||||
if (!fp)
|
||||
{
|
||||
switch (errno)
|
||||
|
@ -486,19 +526,19 @@ int download_file(char *url, const char *savefile)
|
|||
|
||||
int kdk_printer_print_download_remote_file(const char *url, const char *filepath)
|
||||
{
|
||||
printf("[%s] Start\n", __FUNCTION__);
|
||||
// printf("[%s] Start\n", __FUNCTION__);
|
||||
int res = -1;
|
||||
|
||||
int available = check_url(url);
|
||||
if (available == 0)
|
||||
{
|
||||
res = download_file(url, filepath);
|
||||
printf("res = %d.\n", res);
|
||||
// printf("res = %d.\n", res);
|
||||
return res;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s seems to be unavailable.\n", url);
|
||||
// printf("%s seems to be unavailable.\n", url);
|
||||
return available;
|
||||
}
|
||||
|
||||
|
@ -506,7 +546,7 @@ int kdk_printer_print_download_remote_file(const char *url, const char *filepath
|
|||
|
||||
int kdk_printer_get_job_status(const char *printername, int jobid)
|
||||
{
|
||||
printf("[%s] Start\n", __FUNCTION__);
|
||||
// printf("[%s] Start\n", __FUNCTION__);
|
||||
cups_job_t *jobs = NULL;
|
||||
int i;
|
||||
int number_jobs;
|
||||
|
@ -521,7 +561,7 @@ int kdk_printer_get_job_status(const char *printername, int jobid)
|
|||
if (jobs[i].id == jobid)
|
||||
{
|
||||
state = jobs[i].state;
|
||||
printf("[%s] job state is %d\n", __FUNCTION__, jobs[i].state);
|
||||
// printf("[%s] job state is %d\n", __FUNCTION__, jobs[i].state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,6 +101,7 @@ pDriverInfoList kdk_usb_get_list()
|
|||
if (NULL == curnode->data)
|
||||
{
|
||||
klog_err("Request Memory For Data Failed");
|
||||
free(curnode);
|
||||
kdk_usb_free(list);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
#include "../libkybluetooth.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
int i = 0;
|
||||
char *manufacturer = "\0";
|
||||
char *version = "\0";
|
||||
char *name = "\0";
|
||||
char *address = "\0";
|
||||
char *link_mode ="\0";
|
||||
char *link_policy ="\0";
|
||||
char *scomtu = "\0";
|
||||
char *alcmtu = "\0";
|
||||
char *packettype = "\0";
|
||||
char *features = "\0";
|
||||
char *bus = "\0";
|
||||
int **id = kdk_bluetooth_get_device_id();
|
||||
do
|
||||
{
|
||||
printf("id = %d\n",id[i]);
|
||||
manufacturer = kdk_bluetooth_get_manufacturer(i);
|
||||
printf("manufacturer: %s\n", manufacturer);
|
||||
free(manufacturer);
|
||||
version = kdk_bluetooth_get_dev_version(i);
|
||||
printf("version: %s\n", version);
|
||||
free(version);
|
||||
name = kdk_bluetooth_get_name(id[i]);
|
||||
printf("name: %s\n", name);
|
||||
address = kdk_bluetooth_get_address(id[i]);
|
||||
printf("address: %s\n", address);
|
||||
link_mode = kdk_bluetooth_get_link_mode(id[i]);
|
||||
printf("link_mode: %s\n", link_mode);
|
||||
link_policy = kdk_bluetooth_get_link_policy(id[i]);
|
||||
printf("link_policy: %s\n", link_policy);
|
||||
scomtu = kdk_bluetooth_get_scomtu(id[i]);
|
||||
printf("scomtu: %s\n", scomtu);
|
||||
alcmtu = kdk_bluetooth_get_alcmtu(id[i]);
|
||||
printf("alcmtu: %s\n", alcmtu);
|
||||
packettype = kdk_bluetooth_get_packettype(id[i]);
|
||||
printf("packettype: %s\n", packettype);
|
||||
features = kdk_bluetooth_get_features(id[i]);
|
||||
printf("features: %s\n", features);
|
||||
bus = kdk_bluetooth_get_bus(id[i]);
|
||||
printf("bus: %s\n", bus);
|
||||
i++;
|
||||
}while(id[i]);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
#include "../libkydisplay.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
char *vendor = kdk_display_get_vendor();
|
||||
printf("生产厂商:%s\n", vendor);
|
||||
free(vendor);
|
||||
char *product = kdk_display_get_product();
|
||||
printf("型号:%s\n", product);
|
||||
free(product);
|
||||
char *description = kdk_display_get_description();
|
||||
printf("设备类型:%s\n", description);
|
||||
free(description);
|
||||
char *id = kdk_display_get_physical_id();
|
||||
printf("物理id:%s\n", id);
|
||||
free(id);
|
||||
char *bus = kdk_display_get_bus_info();
|
||||
printf("总线地址:%s\n", bus);
|
||||
free(bus);
|
||||
char *version = kdk_display_get_version();
|
||||
printf("设备版本:%s\n", version);
|
||||
free(version);
|
||||
char *width = kdk_display_get_width();
|
||||
printf("数据宽度:%s\n", width);
|
||||
free(width);
|
||||
char *clock = kdk_display_get_clock();
|
||||
printf("频率:%s\n", clock);
|
||||
free(clock);
|
||||
char *capabilities = kdk_display_get_capabilities();
|
||||
printf("功能:%s\n", capabilities);
|
||||
free(capabilities);
|
||||
char *configuration = kdk_display_get_configuration();
|
||||
printf("配置:%s\n", configuration);
|
||||
free(configuration);
|
||||
char *resources = kdk_display_get_resources();
|
||||
printf("资源:%s\n", resources);
|
||||
free(resources);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
#include "../libkyedid.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
char** name = kdk_edid_get_interface();
|
||||
size_t count = 0;
|
||||
// float gamma = 0.00;
|
||||
// float size = 0.00;
|
||||
// char* max_resolution = NULL;
|
||||
// char* model = NULL;
|
||||
// char *area = NULL;
|
||||
// char *manufacturer = NULL;
|
||||
// int week;
|
||||
// int year;
|
||||
// int primary;
|
||||
// char* resolution = NULL;
|
||||
// char *ratio = NULL;
|
||||
// char *character = NULL;
|
||||
while (name[count])
|
||||
{
|
||||
printf("当前接口 = %s\n", name[count]);
|
||||
float gamma = kdk_edid_get_gamma(name[count]);
|
||||
printf("gamma = %0.2f\n", gamma);
|
||||
float size = kdk_edid_get_size(name[count]);
|
||||
printf("size = %0.1f\n", size);
|
||||
char *max_resolution = kdk_edid_get_max_resolution(name[count]);
|
||||
printf("max_resolution = %s\n", max_resolution);
|
||||
free(max_resolution);
|
||||
char *model = kdk_edid_get_model(name[count]);
|
||||
printf("model = %s\n", model);
|
||||
free(model);
|
||||
char *area = kdk_edid_get_visible_area(name[count]);
|
||||
printf("area = %s\n", area);
|
||||
free(area);
|
||||
char *manufacturer = kdk_edid_get_manufacturer(name[count]);
|
||||
printf("manufacturer = %s\n", manufacturer);
|
||||
free(manufacturer);
|
||||
int week = kdk_edid_get_week(name[count]);
|
||||
printf("week = %d\n", week);
|
||||
int year = kdk_edid_get_year(name[count]);
|
||||
printf("year = %d\n", year);
|
||||
int primary = kdk_edid_get_primary(name[count]);
|
||||
printf("%s\n", primary == 1 ? "是" : "否");
|
||||
|
||||
char *resolution = kdk_edid_get_resolution(name[count]);
|
||||
printf("resolution = %s\n", resolution);
|
||||
free(resolution);
|
||||
|
||||
char *ratio = kdk_edid_get_ratio(name[count]);
|
||||
printf("ratio = %s\n", ratio);
|
||||
free(ratio);
|
||||
|
||||
char *character = kdk_edid_get_character(name[count]);
|
||||
printf("character = %s\n", character);
|
||||
free(character);
|
||||
|
||||
printf("---------------------------------------\n");
|
||||
count ++;
|
||||
}
|
||||
kdk_edid_freeall(name);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
#include "../libkyfan.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
char **fan = kdk_fan_get_information();
|
||||
int index = 0;
|
||||
while (fan[index])
|
||||
{
|
||||
printf("%s\n", fan[index]);
|
||||
index++;
|
||||
}
|
||||
kdk_fan_freeall(fan);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
#include "../libkyhw.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static _print_hw(struct HWInfo *hw)
|
||||
{
|
||||
struct HWInfo *tmp = hw;
|
||||
while (tmp)
|
||||
{
|
||||
printf("\tmodel : %s\n", tmp->model);
|
||||
printf("\t\tvendor : %s\n", tmp->vendor);
|
||||
printf("\t\tdevice : %s\n", tmp->device);
|
||||
printf("\t\tdriver : %s\n", tmp->driver);
|
||||
printf("\t\trevision : %s\n", tmp->revision);
|
||||
printf("\t\tdevicenum : %s\n", tmp->devicenum);
|
||||
printf("\t\tclock : %s\n", tmp->clock);
|
||||
printf("\t\twidth : %s\n", tmp->width);
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void Traverse_hardware()
|
||||
{
|
||||
struct HWInfo *keyboard = kdk_hw_get_hwinfo(3);
|
||||
printf("KeyBoard Info:\n");
|
||||
_print_hw(keyboard);
|
||||
kdk_hw_free_hw(keyboard);
|
||||
|
||||
struct HWInfo *mouse = kdk_hw_get_hwinfo(5);
|
||||
printf("Mouse Info:\n");
|
||||
_print_hw(mouse);
|
||||
kdk_hw_free_hw(mouse);
|
||||
|
||||
struct HWInfo *bound = kdk_hw_get_hwinfo(15);
|
||||
printf("Bound Info:\n");
|
||||
_print_hw(bound);
|
||||
kdk_hw_free_hw(bound);
|
||||
|
||||
struct HWInfo *cdrom = kdk_hw_get_hwinfo(23);
|
||||
printf("CDRom Info:\n");
|
||||
_print_hw(cdrom);
|
||||
kdk_hw_free_hw(cdrom);
|
||||
|
||||
struct HWInfo *camera = kdk_hw_get_hwinfo(27);
|
||||
printf("Camera Info:\n");
|
||||
_print_hw(camera);
|
||||
kdk_hw_free_hw(camera);
|
||||
}
|
||||
|
||||
static void Traverse_power()
|
||||
{
|
||||
struct Power * power = kdk_hw_get_powerinfo();
|
||||
printf("on_battery : %s\n", power->on_battery ? "true" : "false");
|
||||
printf("lid_is_closed : %s\n", power->lid_is_closed ? "true" : "false");
|
||||
printf("lid_is_present : %s\n", power->lid_is_present ? "true" : "false");
|
||||
printf("daemon version : %s\n", power->daemon_version);
|
||||
printf("critical action : %s\n", power->critical_action);
|
||||
|
||||
struct power_device *tmp = power->devices;
|
||||
while (tmp)
|
||||
{
|
||||
printf("name : %s\n", tmp->name);
|
||||
printf("\tnative path : %s\n", tmp->native_path);
|
||||
printf("\tpower supply : %s\n", tmp->power_supply ? "true" : "false");
|
||||
printf("\tupdated : %s\n", tmp->updated);
|
||||
printf("\thas history : %s\n", tmp->has_history ? "true" : "false");
|
||||
printf("\thas statistics : %s\n", tmp->has_statistics ? "true" : "false");
|
||||
printf("\tis persent: %s\n", tmp->is_persent ? "true" : "false");
|
||||
printf("\tis rechargeable : %s\n", tmp->is_rechargeable ? "true" : "false");
|
||||
printf("\tstate : %s\n", tmp->state);
|
||||
printf("\twaring level : %s\n", tmp->warning_level);
|
||||
printf("\tenergy : %0.2f\n", tmp->energy);
|
||||
printf("\tenergy empty : %0.2f\n", tmp->energy_empty);
|
||||
printf("\tenergy full: %0.2f\n", tmp->energy_full);
|
||||
printf("\tenergy full design : %0.2f\n", tmp->energy_full_design);
|
||||
printf("\tenergy rate : %0.2f\n", tmp->energy_rate);
|
||||
printf("\tvoltage : %0.2f\n", tmp->voltage);
|
||||
printf("\ttime to empty : %ld\n", tmp->time_to_empty);
|
||||
printf("\ttime to full : %ld\n", tmp->time_to_full);
|
||||
printf("\tpercentage : %0.2f\n", tmp->percentage);
|
||||
printf("\ttemperature : %0.2f\n", tmp->temperature);
|
||||
printf("\tcapacity : %0.2f\n", tmp->capacity);
|
||||
printf("\ttechnology : %s\n", tmp->technology);
|
||||
printf("\tonline : %s\n", tmp->online ? "true" : "false");
|
||||
printf("\ticon name : %s\n", tmp->icon_name);
|
||||
tmp = tmp->next;
|
||||
}
|
||||
kdk_hw_free_power_info(power);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("please use like >> kyhwinfo-test --[target]\n");
|
||||
printf("hardware");
|
||||
printf("\tpower");
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
if (0 == strcmp(argv[1], "--hardware"))
|
||||
Traverse_hardware();
|
||||
if (0 == strcmp(argv[1], "--power"))
|
||||
Traverse_power();
|
||||
}
|
|
@ -12,12 +12,13 @@ int main()
|
|||
char *mac = kdk_nc_get_phymac(cards[index]);
|
||||
char *ipv4 = kdk_nc_get_private_ipv4(cards[index]);
|
||||
char *ipv6 = kdk_nc_get_private_ipv6(cards[index]);
|
||||
char *driver = kdk_nc_get_driver(cards[index]);
|
||||
char vendor[256] = "\0", product[256] = "\0";
|
||||
kdk_nc_get_vendor_and_product(cards[index], vendor, product);
|
||||
printf("Card %zd: %s\tStatus: %s\tMac: %s\tIPv4: %s\tIPv6: %s\t Vendor: %s\t Product: %s\t Type: %s\n",
|
||||
printf("Card %zd: %s\tStatus: %s\tMac: %s\tIPv4: %s\tIPv6: %s\t Vendor: %s\t Product: %s\t Type: %s\t driver: %s\n",
|
||||
index + 1, cards[index], kdk_nc_is_up(cards[index]) == 1 ? "Up" : "Down",
|
||||
mac, ipv4, ipv6, vendor, product,
|
||||
kdk_nc_is_wireless(cards[index]) ? "wireless" : "ethernet");
|
||||
kdk_nc_is_wireless(cards[index]) ? "wireless" : "ethernet", driver);
|
||||
|
||||
char **list4 = kdk_nc_get_ipv4(cards[index]);
|
||||
int i = 0;
|
||||
|
@ -40,6 +41,7 @@ int main()
|
|||
free(ipv6);
|
||||
free(list4);
|
||||
free(list6);
|
||||
free(driver);
|
||||
index++;
|
||||
}
|
||||
kdk_nc_freeall(cards);
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/../../.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
Binary file not shown.
|
@ -141,7 +141,7 @@ public class Main {
|
|||
public static void resource(){
|
||||
ResourceMethod obj = new ResourceMethod();
|
||||
System.out.println("Total:" + obj.getMemTotalKiB());
|
||||
System.out.println("UsagePer:" + obj.getMemSwapUsagePercent());
|
||||
System.out.println("UsagePer:" + obj.getMemUsagePercent());
|
||||
System.out.println("Usage:" + obj.getMemUsageKiB());
|
||||
System.out.println("Avail:" + obj.getMemAvailableKiB());
|
||||
System.out.println("Free:" + obj.getMemFreeKiB());
|
||||
|
@ -254,4 +254,4 @@ public class Main {
|
|||
if(args.length == 5)
|
||||
obj.setPrinterOptions(Integer.parseInt(args[1]),args[2],args[3],args[4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,3 +6,4 @@ Name=SDK-SYSTEM-SESSION-BUS
|
|||
Icon=
|
||||
Keywords=session;kysdk-dbus-session
|
||||
Comment=This session date you into sdk
|
||||
NoDisplay=true
|
||||
|
|
|
@ -3,4 +3,5 @@ Type=Application
|
|||
Exec=/usr/bin/httpServer
|
||||
Name=kysdk-httpServer
|
||||
Comment=provide kysdk dbus js interface
|
||||
X-MATE_Autostart-Delay=15
|
||||
X-MATE_Autostart-Delay=15
|
||||
NoDisplay=true
|
||||
|
|
|
@ -3,4 +3,5 @@ Type=Application
|
|||
Exec=/usr/bin/kysdk-dbus-websocket
|
||||
Name=kysdk-dbus-websocket
|
||||
Comment=provide kysdk dbus js interface
|
||||
X-MATE_Autostart-Delay=15
|
||||
X-MATE_Autostart-Delay=15
|
||||
NoDisplay=true
|
||||
|
|
|
@ -1,10 +1,154 @@
|
|||
#include "libkynetinfo.h"
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/route.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <kysdk/kysdk-base/cstring-extension.h>
|
||||
|
||||
enum cardstat
|
||||
{
|
||||
NCSTAT_LINK_UP,
|
||||
NCSTAT_LINK_DOWN,
|
||||
NCSTAT_ERROR
|
||||
};
|
||||
|
||||
#define PROGNAME_WIDTH 20
|
||||
#define SELINUX_WIDTH 50
|
||||
#define PRG_HASH_SIZE 211
|
||||
|
||||
static struct prg_node
|
||||
{
|
||||
struct prg_node *next;
|
||||
unsigned long inode;
|
||||
char name[PROGNAME_WIDTH];
|
||||
char scon[SELINUX_WIDTH];
|
||||
} * prg_hash[PRG_HASH_SIZE];
|
||||
|
||||
static char prg_cache_loaded = 0;
|
||||
|
||||
#define PRG_HASHIT(x) ((x) % PRG_HASH_SIZE)
|
||||
|
||||
#define PRG_LOCAL_ADDRESS "local_address"
|
||||
#define PRG_INODE "inode"
|
||||
#define PRG_SOCKET_PFX "socket:["
|
||||
#define PRG_SOCKET_PFXl (strlen(PRG_SOCKET_PFX))
|
||||
#define PRG_SOCKET_PFX2 "[0000]:"
|
||||
#define PRG_SOCKET_PFX2l (strlen(PRG_SOCKET_PFX2))
|
||||
|
||||
#ifndef LINE_MAX
|
||||
#define LINE_MAX 4096
|
||||
#endif
|
||||
|
||||
#define PATH_PROC "/proc"
|
||||
#define PATH_FD_SUFF "fd"
|
||||
#define PATH_FD_SUFFl strlen(PATH_FD_SUFF)
|
||||
#define PATH_PROC_X_FD PATH_PROC "/%s/" PATH_FD_SUFF
|
||||
#define PATH_CMDLINE "cmdline"
|
||||
#define PATH_CMDLINEl strlen(PATH_CMDLINE)
|
||||
|
||||
uint verify_file(char *pFileName)
|
||||
{
|
||||
return !strncmp(pFileName, "/proc", strlen("/proc"));
|
||||
}
|
||||
|
||||
static char *safe_strncpy(char *dst, const char *src, size_t size)
|
||||
{
|
||||
dst[size - 1] = '\0';
|
||||
return strncpy(dst, src, size - 1);
|
||||
}
|
||||
|
||||
static void prg_cache_add(unsigned long inode, char *name, const char *scon)
|
||||
{
|
||||
unsigned hi = PRG_HASHIT(inode);
|
||||
struct prg_node **pnp, *pn;
|
||||
|
||||
prg_cache_loaded = 2;
|
||||
for (pnp = prg_hash + hi; (pn = *pnp); pnp = &pn->next)
|
||||
{
|
||||
if (pn->inode == inode)
|
||||
{
|
||||
/* Some warning should be appropriate here
|
||||
as we got multiple processes for one i-node */
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!(*pnp = (struct prg_node *)malloc(sizeof(**pnp))))
|
||||
return;
|
||||
pn = *pnp;
|
||||
pn->next = NULL;
|
||||
pn->inode = inode;
|
||||
safe_strncpy(pn->name, name, sizeof(pn->name));
|
||||
|
||||
{
|
||||
int len = (strlen(scon) - sizeof(pn->scon)) + 1;
|
||||
if (len > 0)
|
||||
safe_strncpy(pn->scon, &scon[len + 1], sizeof(pn->scon));
|
||||
else
|
||||
safe_strncpy(pn->scon, scon, sizeof(pn->scon));
|
||||
}
|
||||
}
|
||||
|
||||
static int extract_type_1_socket_inode(const char lname[], unsigned long *inode_p)
|
||||
{
|
||||
|
||||
/* If lname is of the form "socket:[12345]", extract the "12345"
|
||||
as *inode_p. Otherwise, return -1 as *inode_p.
|
||||
*/
|
||||
|
||||
if (strlen(lname) < PRG_SOCKET_PFXl + 3)
|
||||
return (-1);
|
||||
|
||||
if (memcmp(lname, PRG_SOCKET_PFX, PRG_SOCKET_PFXl))
|
||||
return (-1);
|
||||
if (lname[strlen(lname) - 1] != ']')
|
||||
return (-1);
|
||||
|
||||
{
|
||||
char inode_str[strlen(lname + 1)]; /* e.g. "12345" */
|
||||
const int inode_str_len = strlen(lname) - PRG_SOCKET_PFXl - 1;
|
||||
char *serr;
|
||||
|
||||
strncpy(inode_str, lname + PRG_SOCKET_PFXl, inode_str_len);
|
||||
inode_str[inode_str_len] = '\0';
|
||||
*inode_p = strtoul(inode_str, &serr, 0);
|
||||
if (!serr || *serr || *inode_p == ~0)
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int extract_type_2_socket_inode(const char lname[], unsigned long *inode_p)
|
||||
{
|
||||
|
||||
/* If lname is of the form "[0000]:12345", extract the "12345"
|
||||
as *inode_p. Otherwise, return -1 as *inode_p.
|
||||
*/
|
||||
|
||||
if (strlen(lname) < PRG_SOCKET_PFX2l + 1)
|
||||
return (-1);
|
||||
if (memcmp(lname, PRG_SOCKET_PFX2, PRG_SOCKET_PFX2l))
|
||||
return (-1);
|
||||
|
||||
{
|
||||
char *serr;
|
||||
|
||||
*inode_p = strtoul(lname + PRG_SOCKET_PFX2l, &serr, 0);
|
||||
if (!serr || *serr || *inode_p == ~0)
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void parse_port_state(int *st, int port, FILE *fp)
|
||||
{
|
||||
char line[1024] = "\0";
|
||||
|
@ -130,7 +274,6 @@ prouteMapList kdk_net_get_route()
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* # cat /proc/net/route
|
||||
* Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
|
||||
|
@ -147,13 +290,11 @@ prouteMapList kdk_net_get_route()
|
|||
kdk_net_free_route(list);
|
||||
goto ERROR;
|
||||
}
|
||||
|
||||
struct sockaddr_in sin;
|
||||
memset(&sin, 0, sizeof(struct sockaddr_in));
|
||||
memcpy(&sin.sin_addr, &g, 4);
|
||||
strcpy(currnode->name, devname);
|
||||
strcpy(currnode->addr, inet_ntoa(sin.sin_addr));
|
||||
|
||||
if (!list)
|
||||
list = currnode;
|
||||
else
|
||||
|
@ -277,3 +418,487 @@ void kdk_net_free_chain(pChain list)
|
|||
free(tmpChain);
|
||||
}
|
||||
}
|
||||
|
||||
static enum cardstat _get_card_stat(const char *nc)
|
||||
{
|
||||
int sfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (!sfd)
|
||||
{
|
||||
// klog_err("网卡[%s]状态获取失败:%s\n", nc, strerror(errno));
|
||||
return NCSTAT_ERROR;
|
||||
}
|
||||
|
||||
struct ifreq stIf;
|
||||
strcpy(stIf.ifr_ifrn.ifrn_name, nc);
|
||||
|
||||
if (ioctl(sfd, SIOCGIFFLAGS, &stIf) < 0)
|
||||
{
|
||||
// klog_err("网卡[%s]状态获取失败:%s\n", nc, strerror(errno));
|
||||
close(sfd);
|
||||
return NCSTAT_ERROR;
|
||||
}
|
||||
|
||||
// close(sfd);
|
||||
if (stIf.ifr_ifru.ifru_flags & IFF_RUNNING)
|
||||
return NCSTAT_LINK_UP;
|
||||
|
||||
return NCSTAT_LINK_DOWN;
|
||||
}
|
||||
|
||||
void kdk_net_get_netmask(IN const char* nc, OUT char *mask)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strcpy(ifr.ifr_name, nc);
|
||||
int ret = ioctl(fd, SIOCGIFNETMASK, &ifr);
|
||||
if (0 != ret)
|
||||
{
|
||||
return;
|
||||
}
|
||||
struct sockaddr_in sin_addr;
|
||||
if(NCSTAT_LINK_UP == _get_card_stat(nc))
|
||||
strcpy(mask, (char *)inet_ntoa(((struct sockaddr_in *)(&ifr.ifr_netmask))->sin_addr));
|
||||
else
|
||||
strcpy(mask,"-");
|
||||
}
|
||||
|
||||
static const char *prg_cache_get(unsigned long inode)
|
||||
{
|
||||
unsigned hi = PRG_HASHIT(inode);
|
||||
struct prg_node *pn;
|
||||
|
||||
for (pn = prg_hash[hi]; pn; pn = pn->next)
|
||||
if (pn->inode == inode)
|
||||
return (pn->name);
|
||||
return ("-");
|
||||
}
|
||||
|
||||
static void prg_cache_clear()
|
||||
{
|
||||
struct prg_node **pnp, *pn;
|
||||
|
||||
if (prg_cache_loaded == 2)
|
||||
for (pnp = prg_hash; pnp < prg_hash + PRG_HASH_SIZE; pnp++)
|
||||
while ((pn = *pnp))
|
||||
{
|
||||
*pnp = pn->next;
|
||||
free(pn);
|
||||
}
|
||||
prg_cache_loaded = 0;
|
||||
}
|
||||
|
||||
static void prg_cache_load(void)
|
||||
{
|
||||
char line[LINE_MAX], eacces = 0;
|
||||
int procfdlen, fd, cmdllen, lnamelen;
|
||||
char lname[30], cmdlbuf[512], finbuf[PROGNAME_WIDTH];
|
||||
unsigned long inode;
|
||||
const char *cs, *cmdlp;
|
||||
DIR *dirproc = NULL, *dirfd = NULL;
|
||||
struct dirent *direproc, *direfd;
|
||||
#if HAVE_SELINUX
|
||||
security_context_t scon = NULL;
|
||||
#endif
|
||||
|
||||
prg_cache_loaded = 1;
|
||||
cmdlbuf[sizeof(cmdlbuf) - 1] = '\0';
|
||||
if (!(dirproc = opendir(PATH_PROC)))
|
||||
goto fail;
|
||||
while (errno = 0, direproc = readdir(dirproc))
|
||||
{
|
||||
for (cs = direproc->d_name; *cs; cs++)
|
||||
if (!isdigit(*cs))
|
||||
break;
|
||||
if (*cs)
|
||||
continue;
|
||||
procfdlen = snprintf(line, sizeof(line), PATH_PROC_X_FD, direproc->d_name);
|
||||
if (procfdlen <= 0 || procfdlen >= sizeof(line) - 5)
|
||||
continue;
|
||||
errno = 0;
|
||||
char canonical_filename[4096] = {"\0"};
|
||||
char filename[4096] = {"\0"};
|
||||
if(!realpath(line, canonical_filename) || !verify_file(canonical_filename))
|
||||
{
|
||||
closedir(dirproc);
|
||||
return;
|
||||
}
|
||||
dirfd = opendir(canonical_filename);
|
||||
if (!dirfd)
|
||||
{
|
||||
if (errno == EACCES)
|
||||
eacces = 1;
|
||||
continue;
|
||||
}
|
||||
canonical_filename[procfdlen] = '/';
|
||||
cmdlp = NULL;
|
||||
while ((direfd = readdir(dirfd)))
|
||||
{
|
||||
/* Skip . and .. */
|
||||
if (!isdigit(direfd->d_name[0]))
|
||||
continue;
|
||||
if (procfdlen + 1 + strlen(direfd->d_name) + 1 > sizeof(canonical_filename))
|
||||
continue;
|
||||
memcpy(canonical_filename + procfdlen - PATH_FD_SUFFl, PATH_FD_SUFF "/",
|
||||
PATH_FD_SUFFl + 1);
|
||||
safe_strncpy(canonical_filename + procfdlen + 1, direfd->d_name,
|
||||
sizeof(canonical_filename) - procfdlen - 1);
|
||||
lnamelen = readlink(canonical_filename, lname, sizeof(lname) - 1);
|
||||
if (lnamelen == -1)
|
||||
continue;
|
||||
lname[lnamelen] = '\0'; /*make it a null-terminated string*/
|
||||
|
||||
if (extract_type_1_socket_inode(lname, &inode) < 0)
|
||||
if (extract_type_2_socket_inode(lname, &inode) < 0)
|
||||
continue;
|
||||
|
||||
if (!cmdlp)
|
||||
{
|
||||
if (procfdlen - PATH_FD_SUFFl + PATH_CMDLINEl >=
|
||||
sizeof(canonical_filename) - 5)
|
||||
continue;
|
||||
safe_strncpy(canonical_filename + procfdlen - PATH_FD_SUFFl, PATH_CMDLINE,
|
||||
sizeof(canonical_filename) - procfdlen + PATH_FD_SUFFl);
|
||||
if(!realpath(canonical_filename, filename) || !verify_file(filename))
|
||||
{
|
||||
closedir(dirfd);
|
||||
closedir(dirproc);
|
||||
return;
|
||||
}
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
continue;
|
||||
cmdllen = read(fd, cmdlbuf, sizeof(cmdlbuf) - 1);
|
||||
if (close(fd))
|
||||
continue;
|
||||
if (cmdllen == -1)
|
||||
continue;
|
||||
if (cmdllen < sizeof(cmdlbuf) - 1)
|
||||
cmdlbuf[cmdllen] = '\0';
|
||||
if (cmdlbuf[0] == '/' && (cmdlp = strrchr(cmdlbuf, '/')))
|
||||
cmdlp++;
|
||||
else
|
||||
cmdlp = cmdlbuf;
|
||||
}
|
||||
|
||||
snprintf(finbuf, sizeof(finbuf), "%s/%s", direproc->d_name, cmdlp);
|
||||
#if HAVE_SELINUX
|
||||
if (getpidcon(atoi(direproc->d_name), &scon) == -1)
|
||||
{
|
||||
scon = xstrdup("-");
|
||||
}
|
||||
prg_cache_add(inode, finbuf, scon);
|
||||
freecon(scon);
|
||||
#else
|
||||
prg_cache_add(inode, finbuf, "-");
|
||||
#endif
|
||||
}
|
||||
closedir(dirfd);
|
||||
dirfd = NULL;
|
||||
}
|
||||
if (dirproc)
|
||||
closedir(dirproc);
|
||||
if (dirfd)
|
||||
closedir(dirfd);
|
||||
if (!eacces)
|
||||
return;
|
||||
if (prg_cache_loaded == 1)
|
||||
{
|
||||
fail:
|
||||
fprintf(stderr, "(No info could be read for \"-p\": geteuid()=%d but you should be root.)\n",
|
||||
geteuid());
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "(Not all processes could be identified, non-owned process info\n"
|
||||
" will not be shown, you would have to be root to see it all.)\n");
|
||||
}
|
||||
|
||||
char **kdk_net_get_proc_port()
|
||||
{
|
||||
prg_cache_load();
|
||||
char **result = NULL;
|
||||
int index = -1;
|
||||
|
||||
char line[1024] = "\0";
|
||||
unsigned long rxq, txq, time_len, retr, inode;
|
||||
int num, local_port, rem_port, d, state, uid, timer_run, timeout;
|
||||
char rem_addr[128] = "0", local_addr[128] = "0";
|
||||
|
||||
FILE *fp = fopen("/proc/net/tcp", "r");
|
||||
if (!fp)
|
||||
return NULL;
|
||||
while (fgets(line, 1024, fp))
|
||||
{
|
||||
num = sscanf(line,
|
||||
"%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %lu %*s\n",
|
||||
&d, local_addr, &local_port, rem_addr, &rem_port, &state,
|
||||
&txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode);
|
||||
const char *proc = prg_cache_get(inode);
|
||||
if (0 == strcmp(proc,"-"))
|
||||
continue;
|
||||
|
||||
index++;
|
||||
result = (char **)realloc(result, sizeof(char *) * (index + 1 + 1)); //以NULL结尾
|
||||
result[index] = (char *)calloc(1, 64);
|
||||
sprintf(result[index], "%d/%s/%s", local_port,proc,"tcp");
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
fp = fopen("/proc/net/tcp6", "r");
|
||||
if (!fp)
|
||||
{
|
||||
while (result && (index >= 0))
|
||||
{
|
||||
free(result[index--]);
|
||||
}
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
while (fgets(line, 1024, fp))
|
||||
{
|
||||
num = sscanf(line,
|
||||
"%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %lu %*s\n",
|
||||
&d, local_addr, &local_port, rem_addr, &rem_port, &state,
|
||||
&txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode);
|
||||
const char *proc = prg_cache_get(inode);
|
||||
if (0 == strcmp(proc, "-"))
|
||||
continue;
|
||||
|
||||
index++;
|
||||
result = (char **)realloc(result, sizeof(char *) * (index + 1 + 1)); // 以NULL结尾
|
||||
result[index] = (char *)calloc(1, 64);
|
||||
sprintf(result[index], "%d/%s/%s", local_port, proc, "tcp6");
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
fp = fopen("/proc/net/udp", "r");
|
||||
if (!fp)
|
||||
{
|
||||
while (result && (index >= 0))
|
||||
{
|
||||
free(result[index--]);
|
||||
}
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
while (fgets(line, 1024, fp))
|
||||
{
|
||||
num = sscanf(line,
|
||||
"%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %lu %*s\n",
|
||||
&d, local_addr, &local_port, rem_addr, &rem_port, &state,
|
||||
&txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode);
|
||||
const char *proc = prg_cache_get(inode);
|
||||
if (0 == strcmp(proc, "-"))
|
||||
continue;
|
||||
|
||||
index++;
|
||||
result = (char **)realloc(result, sizeof(char *) * (index + 1 + 1)); //以NULL结尾
|
||||
result[index] = (char *)calloc(1, 64);
|
||||
sprintf(result[index], "%d/%s/%s", local_port, proc, "udp");
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
fp = fopen("/proc/net/udp6", "r");
|
||||
if (!fp)
|
||||
{
|
||||
while (result && (index >= 0))
|
||||
{
|
||||
free(result[index--]);
|
||||
}
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
while (fgets(line, 1024, fp))
|
||||
{
|
||||
num = sscanf(line,
|
||||
"%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %lu %*s\n",
|
||||
&d, local_addr, &local_port, rem_addr, &rem_port, &state,
|
||||
&txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode);
|
||||
const char *proc = prg_cache_get(inode);
|
||||
if (0 == strcmp(proc, "-"))
|
||||
continue;
|
||||
|
||||
index++;
|
||||
result = (char **)realloc(result, sizeof(char *) * (index + 1 + 1)); // 以NULL结尾
|
||||
result[index] = (char *)calloc(1, 64);
|
||||
sprintf(result[index], "%d/%s/%s", local_port, proc, "udp6");
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
result[index + 1] = NULL;
|
||||
|
||||
prg_cache_clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
char **kdk_net_get_up_port()
|
||||
{
|
||||
char **result = NULL;
|
||||
int index = -1;
|
||||
FILE *fp = fopen("/proc/net/tcp", "r");
|
||||
if (!fp)
|
||||
return NULL;
|
||||
char line[1024] = "\0";
|
||||
unsigned long rxq, txq, time_len, retr, inode;
|
||||
int num, local_port, rem_port, d, state, uid, timer_run, timeout;
|
||||
char rem_addr[128] = "0", local_addr[128] = "0";
|
||||
while (fgets(line, 1024, fp))
|
||||
{
|
||||
num = sscanf(line,
|
||||
"%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %lu %*s\n",
|
||||
&d, local_addr, &local_port, rem_addr, &rem_port, &state,
|
||||
&txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode);
|
||||
if (0x0a == state)
|
||||
{
|
||||
int i = 0;
|
||||
int flag = 1;
|
||||
while (i <= index) //查重
|
||||
{
|
||||
if (local_port == atoi(result[i++]))
|
||||
flag = 0; //有重复 flag置为1
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
index++;
|
||||
result = (char **)realloc(result, sizeof(char *) * (index + 1 + 1)); // 以NULL结尾
|
||||
if (!result)
|
||||
goto error;
|
||||
result[index] = (char *)calloc(1, 8);
|
||||
if (!result[index])
|
||||
goto error;
|
||||
sprintf(result[index], "%d", local_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
result[index + 1] = NULL;
|
||||
return result;
|
||||
error:
|
||||
for(int i = 0; result[i]; i++)
|
||||
{
|
||||
free(result[i]);
|
||||
}
|
||||
free(result);
|
||||
result = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* kdk_net_get_hosts()
|
||||
{
|
||||
FILE *fp = fopen("/etc/hosts", "r");
|
||||
if (fp == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *hosts = (char *)malloc(sizeof(char) * 64);
|
||||
if (hosts == NULL)
|
||||
{
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
char line[4096] = "\0";
|
||||
memset(hosts, 0, sizeof(hosts));
|
||||
while (fgets(line, sizeof(line), fp))
|
||||
{
|
||||
strcat(hosts, line);
|
||||
if(line[0] == '\n')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
strstripspace(hosts);
|
||||
return hosts;
|
||||
}
|
||||
|
||||
char* kdk_net_get_hosts_domain()
|
||||
{
|
||||
FILE *fp = fopen("/etc/hosts", "r");
|
||||
if (fp == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *hosts = (char *)malloc(sizeof(char) * 64);
|
||||
if (hosts == NULL)
|
||||
{
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
char line[4096] = "\0";
|
||||
memset(hosts, 0, sizeof(hosts));
|
||||
int i = 0;
|
||||
while (fgets(line, sizeof(line), fp))
|
||||
{
|
||||
if(2 == i && '\n' == line[0] )
|
||||
continue;
|
||||
|
||||
if(line[0] == '\n')
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
// strcat(hosts, line);
|
||||
if(i == 2)
|
||||
{
|
||||
strcat(hosts, line);
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
strstripspace(hosts);
|
||||
return hosts;
|
||||
}
|
||||
|
||||
char** kdk_net_get_resolv_conf()
|
||||
{
|
||||
char nserver[16] = "\0";
|
||||
char addr[16] = "\0";
|
||||
char **result = NULL;
|
||||
result = (char **)realloc(result, sizeof(char *) * 128); //以NULL结尾
|
||||
if(!result)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
int index = 0;
|
||||
FILE *fp = fopen("/etc/resolv.conf", "r");
|
||||
if (fp == NULL)
|
||||
{
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char line[4096] = "\0";
|
||||
while (fgets(line, sizeof(line), fp))
|
||||
{
|
||||
if(strstr(line,"nameserver"))
|
||||
{
|
||||
result[index] = (char *)malloc(sizeof(char) * 128);
|
||||
if(!result[index])
|
||||
{
|
||||
fclose(fp);
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
sscanf(line, "%s %s", nserver, addr);
|
||||
strcpy(result[index], addr);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
result[index] = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void kdk_net_freeall(char **list)
|
||||
{
|
||||
if (!list)
|
||||
return;
|
||||
size_t index = 0;
|
||||
while (list[index])
|
||||
{
|
||||
free(list[index]);
|
||||
index++;
|
||||
}
|
||||
free(list);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#ifndef LIBKYNETINFO_H
|
||||
#define LIBKYNETINFO_H
|
||||
|
||||
#define IN
|
||||
#define OUT
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
|
@ -48,6 +51,59 @@ extern "C"
|
|||
|
||||
extern void kdk_net_free_chain(pChain list);
|
||||
|
||||
/**
|
||||
* @brief 获取子网信息
|
||||
*
|
||||
* @param nc 网卡名称,如eno1
|
||||
* @param mask 子网掩码
|
||||
*
|
||||
*/
|
||||
extern void kdk_net_get_netmask(IN const char *nc, OUT char *mask);
|
||||
|
||||
/**
|
||||
* @brief 获取进程对应端口
|
||||
*
|
||||
*
|
||||
* @return char ** 进程对应端口
|
||||
*/
|
||||
extern char **kdk_net_get_proc_port();
|
||||
|
||||
/**
|
||||
* @brief 获取所有UP状态的端口号
|
||||
*
|
||||
*
|
||||
* @return char ** 所有UP状态的端口号
|
||||
*/
|
||||
extern char **kdk_net_get_up_port();
|
||||
|
||||
/**
|
||||
* @brief 获取hosts配置
|
||||
*
|
||||
* @return char* hosts配置
|
||||
*/
|
||||
extern char* kdk_net_get_hosts();
|
||||
|
||||
/**
|
||||
* @brief 获取hosts配置的域名映射
|
||||
*
|
||||
* @return char* hosts配置的域名映射
|
||||
*/
|
||||
extern char* kdk_net_get_hosts_domain();
|
||||
|
||||
/**
|
||||
* @brief 获取DNS配置文件
|
||||
*
|
||||
* @return char** DNS配置文件
|
||||
*/
|
||||
extern char** kdk_net_get_resolv_conf();
|
||||
|
||||
/**
|
||||
* @brief 用于回收字符串列表
|
||||
*
|
||||
* @param ptr 字符串列表
|
||||
*/
|
||||
extern inline void kdk_net_freeall(char **ptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -42,5 +42,51 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
else
|
||||
printf("Failed With %d", net);
|
||||
printf("\n");
|
||||
printf("\n");
|
||||
|
||||
char mask[32] = "\0";
|
||||
kdk_net_get_netmask("enaftgm1i0", mask);
|
||||
printf("mask = %s\n", mask);
|
||||
|
||||
char **port = kdk_net_get_proc_port();
|
||||
size_t index = 0;
|
||||
while(port[index])
|
||||
{
|
||||
printf("No.%ld, port = %s\n", index+1, port[index]);
|
||||
index++;
|
||||
}
|
||||
kdk_net_freeall(port);
|
||||
|
||||
port = kdk_net_get_up_port();
|
||||
index = 0;
|
||||
while(port[index])
|
||||
{
|
||||
printf("No.%ld, port = %s\n", index+1, port[index]);
|
||||
index++;
|
||||
}
|
||||
kdk_net_freeall(port);
|
||||
|
||||
char *hosts = kdk_net_get_hosts();
|
||||
if (hosts != NULL)
|
||||
{
|
||||
printf("hosts = %s\n", hosts);
|
||||
free(hosts);
|
||||
}
|
||||
|
||||
char *domain = kdk_net_get_hosts_domain();
|
||||
if (domain != NULL)
|
||||
{
|
||||
printf("domain = %s\n", domain);
|
||||
free(domain);
|
||||
}
|
||||
|
||||
char **resolv = kdk_net_get_resolv_conf();
|
||||
index = 0;
|
||||
while(resolv[index])
|
||||
{
|
||||
printf("No.%ld, resolv = %s\n", index+1, resolv[index]);
|
||||
index++;
|
||||
}
|
||||
kdk_net_freeall(resolv);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <libkylog.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#define PRG_SOCKET_PFX "socket:["
|
||||
#define PRG_SOCKET_PFXl (strlen(PRG_SOCKET_PFX))
|
||||
|
@ -27,7 +28,7 @@
|
|||
#define MAX_PF_NAME 1024
|
||||
#define PROC_DIR "/proc"
|
||||
#define MAX_PROC_NUM 1024
|
||||
#define PROC_NUM 500
|
||||
#define PROC_NUM 1024 * 5
|
||||
#define BUF_SIZE 1024
|
||||
static int uptime_fd = -1;
|
||||
#define LC_NUMERIC __LC_NUMERIC
|
||||
|
@ -299,6 +300,132 @@ unsigned long get_cpu_proc_occupy(unsigned int pid)
|
|||
return (t.utime + t.stime + t.cutime + t.cstime);
|
||||
}
|
||||
|
||||
char* kdk_get_process_name(int proc_num)
|
||||
{
|
||||
char path[100] = "\0";
|
||||
char *name = (char *)malloc(sizeof(char) * 64);
|
||||
if(!name)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
char link[64] = "\0";
|
||||
char buffer[1025] = "\0";
|
||||
sprintf(path, "/proc/%d/exe", proc_num);
|
||||
|
||||
int count = readlink(path, link, sizeof(link));
|
||||
if(count != -1)
|
||||
{
|
||||
strcpy(name, basename(link));
|
||||
}
|
||||
else{
|
||||
memset(path, 0, sizeof(path));
|
||||
sprintf(path, "/proc/%d/status", proc_num);
|
||||
FILE *fp = fopen(path, "rt");
|
||||
if (!fp)
|
||||
{
|
||||
free(name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), fp))
|
||||
{
|
||||
if (lookup(buffer, "Name", &name))
|
||||
break;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
int kdk_get_process_id(char *proc_name)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *ptr;
|
||||
FILE *fp;
|
||||
char path[512] = "\0";
|
||||
int i = 0;
|
||||
char *realpath_res = NULL;
|
||||
char *canonical_filename = NULL;
|
||||
size_t path_size = 0;
|
||||
path_size = (size_t)PATH_MAX;
|
||||
char line[1024] = {0};
|
||||
char *name = NULL;
|
||||
char link[128] = "\0";
|
||||
int res = 0;
|
||||
|
||||
dir = opendir("/proc");
|
||||
if (NULL != dir)
|
||||
{
|
||||
while ((ptr = readdir(dir)) != NULL) //循环读取/proc下的每一个文件/文件夹
|
||||
{
|
||||
//如果读取到的是"."或者".."则跳过,读取到的不是文件夹名字也跳过
|
||||
if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0))
|
||||
continue;
|
||||
if (DT_DIR != ptr->d_type)
|
||||
continue;
|
||||
|
||||
sprintf(path, "/proc/%s/exe", ptr->d_name); //生成要读取的文件的路径
|
||||
memset(link, 0, sizeof(link));
|
||||
int count = readlink(path, link, sizeof(link));
|
||||
if(count != -1)
|
||||
{
|
||||
if ((strcmp(basename(link), proc_name)) == 0)
|
||||
{
|
||||
sscanf(ptr->d_name, "%d", &res);
|
||||
}
|
||||
}
|
||||
else{
|
||||
memset(path, 0, sizeof(path));
|
||||
sprintf(path, "/proc/%s/status", ptr->d_name);
|
||||
if (path_size > 0)
|
||||
{
|
||||
canonical_filename = malloc(path_size);
|
||||
if (canonical_filename == NULL)
|
||||
{
|
||||
FREE(canonical_filename);
|
||||
continue;
|
||||
}
|
||||
realpath_res = realpath(path, canonical_filename);
|
||||
}
|
||||
if (canonical_filename == NULL)
|
||||
{
|
||||
FREE(canonical_filename);
|
||||
continue;
|
||||
}
|
||||
if (!verify_file(canonical_filename))
|
||||
{
|
||||
FREE(canonical_filename);
|
||||
continue;
|
||||
}
|
||||
|
||||
fp = fopen(canonical_filename, "r");
|
||||
if (fp == NULL)
|
||||
{
|
||||
FREE(canonical_filename);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (fgets(line, sizeof(line), fp))
|
||||
{
|
||||
if (lookup(line, "Name", &name))
|
||||
break;
|
||||
}
|
||||
FREE(canonical_filename);
|
||||
}
|
||||
|
||||
if ((strcmp(name, proc_name)) == 0)
|
||||
{
|
||||
sscanf(ptr->d_name, "%d", &res);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
float kdk_get_process_cpu_usage_percent(int proc_num)
|
||||
{
|
||||
unsigned long totalcputime1, totalcputime2;
|
||||
|
@ -333,6 +460,17 @@ float kdk_get_process_mem_usage_percent(int proc_num)
|
|||
sprintf(path, "/proc/%d/status", proc_num);
|
||||
if (path_size > 0)
|
||||
{
|
||||
canonical_filename = malloc(path_size);
|
||||
if (canonical_filename == NULL)
|
||||
{
|
||||
return 0.00;
|
||||
}
|
||||
if(!realpath(path, canonical_filename) || !verify_file(canonical_filename))
|
||||
{
|
||||
FREE(canonical_filename);
|
||||
return 0.00;
|
||||
}
|
||||
}
|
||||
|
||||
FILE *fp = fopen(canonical_filename, "r");
|
||||
if (!fp)
|
||||
|
@ -351,6 +489,7 @@ float kdk_get_process_mem_usage_percent(int proc_num)
|
|||
|
||||
FILE *fb = fopen(MEMINFO, "rt");
|
||||
if (!fb)
|
||||
goto err;
|
||||
while (fgets(buffers, 1024, fb))
|
||||
{
|
||||
if (lookup_num(buffers, "MemTotal", &memTotal))
|
||||
|
@ -951,7 +1090,7 @@ int **getPidByName(char *task_name)
|
|||
DIR *dir;
|
||||
struct dirent *ptr;
|
||||
FILE *fp;
|
||||
char path[100];
|
||||
char path[512] = "\0";
|
||||
char cur_task_name[50];
|
||||
char buf[BUF_SIZE];
|
||||
int i = 0;
|
||||
|
@ -959,6 +1098,8 @@ int **getPidByName(char *task_name)
|
|||
char *canonical_filename = NULL;
|
||||
size_t path_size = 0;
|
||||
path_size = (size_t)PATH_MAX;
|
||||
char *name = NULL;
|
||||
char link[128] = "\0";
|
||||
int **res = malloc(sizeof(int) * 500);
|
||||
if (!res)
|
||||
{
|
||||
|
@ -985,54 +1126,62 @@ int **getPidByName(char *task_name)
|
|||
if (DT_DIR != ptr->d_type)
|
||||
continue;
|
||||
|
||||
sprintf(path, "/proc/%s/status", ptr->d_name); //生成要读取的文件的路径
|
||||
if (path_size > 0)
|
||||
sprintf(path, "/proc/%s/exe", ptr->d_name); //生成要读取的文件的路径
|
||||
int count = readlink(path, link, sizeof(link));
|
||||
if(count != -1)
|
||||
{
|
||||
canonical_filename = malloc(path_size);
|
||||
if (strstr(basename(link), task_name))
|
||||
{
|
||||
sscanf(ptr->d_name, "%ls", res[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else{
|
||||
memset(path, 0, sizeof(path));
|
||||
sprintf(path, "/proc/%s/status", ptr->d_name);
|
||||
if (path_size > 0)
|
||||
{
|
||||
canonical_filename = malloc(path_size);
|
||||
if (canonical_filename == NULL)
|
||||
{
|
||||
FREE(canonical_filename);
|
||||
continue;
|
||||
}
|
||||
realpath_res = realpath(path, canonical_filename);
|
||||
}
|
||||
if (canonical_filename == NULL)
|
||||
{
|
||||
FREE(canonical_filename);
|
||||
continue;
|
||||
}
|
||||
realpath_res = realpath(path, canonical_filename);
|
||||
}
|
||||
if (canonical_filename == NULL)
|
||||
{
|
||||
FREE(canonical_filename);
|
||||
continue;
|
||||
}
|
||||
if (!verify_file(canonical_filename))
|
||||
{
|
||||
FREE(canonical_filename);
|
||||
continue;
|
||||
}
|
||||
|
||||
fp = fopen(canonical_filename, "r");
|
||||
if (fp == NULL)
|
||||
{
|
||||
FREE(canonical_filename);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fgets(buf, BUF_SIZE - 1, fp) == NULL)
|
||||
if (!verify_file(canonical_filename))
|
||||
{
|
||||
fclose(fp);
|
||||
FREE(canonical_filename);
|
||||
continue;
|
||||
}
|
||||
sscanf(buf, "%*s %s", cur_task_name);
|
||||
|
||||
//如果文件内容满足要求则打印路径的名字(即进程的PID)
|
||||
if (strstr(cur_task_name, task_name))
|
||||
fp = fopen(canonical_filename, "r");
|
||||
if (fp == NULL)
|
||||
{
|
||||
FREE(canonical_filename);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (fgets(buf, sizeof(buf), fp))
|
||||
{
|
||||
if (lookup(buf, "Name", &name))
|
||||
break;
|
||||
}
|
||||
FREE(canonical_filename);
|
||||
}
|
||||
|
||||
if (strstr(name, task_name))
|
||||
{
|
||||
sscanf(ptr->d_name, "%ls", res[i]);
|
||||
i++;
|
||||
}
|
||||
fclose(fp);
|
||||
FREE(canonical_filename);
|
||||
}
|
||||
FREE(canonical_filename);
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
|
@ -1042,13 +1191,18 @@ int **getPidByName(char *task_name)
|
|||
|
||||
char **kdk_procname_get_process_infomation(char *proc_name)
|
||||
{
|
||||
size_t cout = 0;
|
||||
int **pid = getPidByName(proc_name);
|
||||
if (!pid)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
int index = 0;
|
||||
char **res = (char **)malloc(sizeof(char) * PROC_COMD_NUM);
|
||||
if (!res)
|
||||
{
|
||||
klog_err("内存申请失败:%s\n", strerror(errno));
|
||||
size_t cout = 0;
|
||||
cout = 0;
|
||||
while (pid[cout])
|
||||
{
|
||||
free(pid[cout]);
|
||||
|
@ -1131,16 +1285,13 @@ char **kdk_procname_get_process_infomation(char *proc_name)
|
|||
char *proc_uid = kdk_get_process_user(proc_pid);
|
||||
strcat(result, "proc_uid:");
|
||||
strcat(result, proc_uid);
|
||||
free(proc_uid);
|
||||
|
||||
strcpy(res[index], result);
|
||||
index++;
|
||||
}
|
||||
goto out;
|
||||
out:
|
||||
if (!pid)
|
||||
return NULL;
|
||||
size_t cout = 0;
|
||||
cout = 0;
|
||||
while (pid[cout])
|
||||
{
|
||||
free(pid[cout]);
|
||||
|
@ -1165,56 +1316,45 @@ err:
|
|||
|
||||
static int get_proc_name(pid_t pid, char *name)
|
||||
{
|
||||
FILE *fpprocstat = NULL;
|
||||
char procstatf[128] = {0};
|
||||
char line[128] = {0};
|
||||
char *start, *end;
|
||||
char *buf = NULL;
|
||||
int num;
|
||||
char *canonical_filename = NULL;
|
||||
size_t path_size = 0;
|
||||
path_size = (size_t)PATH_MAX;
|
||||
|
||||
char path[100] = "\0";
|
||||
char link[64] = "\0";
|
||||
char *tmp = NULL;
|
||||
char buffer[1025] = "\0";
|
||||
char canonical_filename [PATH_MAX] = "\0";
|
||||
if (pid < 0)
|
||||
return -1;
|
||||
else
|
||||
sprintf(procstatf, "/proc/%d/stat", pid);
|
||||
if (strstr(procstatf, ".."))
|
||||
return -1;
|
||||
sprintf(path, "/proc/%d/exe", pid);
|
||||
|
||||
if (path_size > 0)
|
||||
int count = readlink(path, link, sizeof(link));
|
||||
if(count != -1)
|
||||
{
|
||||
canonical_filename = malloc(path_size);
|
||||
if (canonical_filename == NULL)
|
||||
strcpy(name, basename(link));
|
||||
}
|
||||
else{
|
||||
memset(path, 0, sizeof(path));
|
||||
sprintf(path, "/proc/%d/status", pid);
|
||||
|
||||
if (!realpath(path, canonical_filename) || !verify_file(canonical_filename))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (!realpath(procstatf, canonical_filename) || !verify_file(canonical_filename))
|
||||
FILE *fp = fopen(canonical_filename, "rt");
|
||||
if (!fp)
|
||||
{
|
||||
FREE(canonical_filename);
|
||||
free(name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((fpprocstat = fopen(canonical_filename, "r")) == NULL)
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
fseek(fpprocstat, 0, SEEK_SET);
|
||||
while (fgets(buffer, sizeof(buffer), fp))
|
||||
{
|
||||
if (lookup(buffer, "Name", &tmp))
|
||||
break;
|
||||
}
|
||||
strcpy(name, tmp);
|
||||
|
||||
buf = fgets(line, sizeof(line), fpprocstat);
|
||||
line[strlen(line) + 1] = '\0';
|
||||
start = strchr(line, '(') + 1;
|
||||
end = strrchr(start, ')');
|
||||
num = end - start;
|
||||
strlcpy(name, start, num + 1);
|
||||
fclose(fpprocstat);
|
||||
FREE(canonical_filename);
|
||||
fclose(fp);
|
||||
}
|
||||
return 0;
|
||||
|
||||
err:
|
||||
FREE(canonical_filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int get_proc_state(pid_t pid, char *state)
|
||||
|
@ -1699,7 +1839,7 @@ int get_proc_running_time(pid_t pid, char *proc_time)
|
|||
if(!buff)
|
||||
{
|
||||
klog_err("内存申请失败:%s\n", strerror(errno));
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *canonical_filename = NULL;
|
||||
|
@ -1985,6 +2125,7 @@ char **kdk_get_process_all_information()
|
|||
char tmp[115200] = "\0";
|
||||
size_t counts = 0;
|
||||
char **res = NULL;
|
||||
char **tmpres = NULL;
|
||||
int ret = get_process_info(pp, &proc_num);
|
||||
if (ret == 0)
|
||||
{
|
||||
|
@ -2032,17 +2173,18 @@ char **kdk_get_process_all_information()
|
|||
strcat(result, "proc_port:");
|
||||
sprintf(tmp, "%s", pp[i].proc_port);
|
||||
strcat(result, tmp);
|
||||
res = realloc(res, (proc_num + 3) * sizeof(char *));
|
||||
if (!res)
|
||||
tmpres = realloc(res, (proc_num + 3) * sizeof(char *));
|
||||
if (!tmpres)
|
||||
{
|
||||
klog_err("内存申请失败:%s\n", strerror(errno));
|
||||
free(res);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = tmpres;
|
||||
res[counts] = malloc(115200 * sizeof(char) + 1);
|
||||
if (!res[counts])
|
||||
{
|
||||
kdk_proc_freeall(res);
|
||||
free(tmpres);
|
||||
klog_err("内存申请失败:%s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2066,3 +2208,10 @@ inline void kdk_proc_freeall(char **list)
|
|||
}
|
||||
free(list);
|
||||
}
|
||||
|
||||
inline void kdk_proc_freeid(int *list)
|
||||
{
|
||||
if (! list)
|
||||
return;
|
||||
free(list);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,22 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 获取某一进程的名称
|
||||
*
|
||||
* @param proc_num 进程号
|
||||
* @return char* 进程的名称
|
||||
*/
|
||||
extern char* kdk_get_process_name(int proc_num);
|
||||
|
||||
/**
|
||||
* @brief 获取某一进程的id
|
||||
*
|
||||
* @param proc_name 进程的名称
|
||||
* @return int** 进程号(id)
|
||||
*/
|
||||
extern int kdk_get_process_id(char *proc_name);
|
||||
|
||||
/**
|
||||
* @brief 获取某一进程的CPU使用率
|
||||
*
|
||||
|
@ -115,6 +131,12 @@ extern char** kdk_get_process_all_information();
|
|||
*/
|
||||
extern inline void kdk_proc_freeall(char **ptr);
|
||||
|
||||
/**
|
||||
* @brief 用于回收进程id资源
|
||||
*
|
||||
* @param list 进程id列表
|
||||
*/
|
||||
extern inline void kdk_proc_freeid(int *list);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -4,31 +4,31 @@
|
|||
|
||||
int main()
|
||||
{
|
||||
char *run_time = kdk_get_process_running_time(841);
|
||||
char *cpu_time = kdk_get_process_cpu_time(841);
|
||||
char *cmd = kdk_get_process_command(841);
|
||||
char *start_time = kdk_get_process_start_time(841);
|
||||
printf("获取某一进程的CPU利用率:%0.1f\n", kdk_get_process_cpu_usage_percent(841));
|
||||
printf("获取某一进程的内存占用率:%0.1f\n", kdk_get_process_mem_usage_percent(841));
|
||||
printf("获取某一进程的进程状态:%s\n", kdk_get_process_status(841));
|
||||
printf("获取某一进程的进程端口号:%d\n", kdk_get_process_port(841));
|
||||
printf("获取某一进程的启动时间:%s\n", start_time);
|
||||
printf("获取某一进程的运行时间:%s\n", run_time);
|
||||
printf("获取某一进程的CPU时间:%s\n", cpu_time);
|
||||
printf("获取某一进程的Command:%s\n", cmd);
|
||||
printf("获取某一进程的属主:%s\n", kdk_get_process_user(841));
|
||||
free(run_time);
|
||||
free(cpu_time);
|
||||
free(cmd);
|
||||
free(start_time);
|
||||
char** pid = kdk_procname_get_process_infomation("qax");
|
||||
size_t index = 0;
|
||||
while (pid[index])
|
||||
{
|
||||
printf("pid %s\n", pid[index]);
|
||||
index ++;
|
||||
}
|
||||
kdk_proc_freeall(pid);
|
||||
// char *run_time = kdk_get_process_running_time(841);
|
||||
// char *cpu_time = kdk_get_process_cpu_time(841);
|
||||
// char *cmd = kdk_get_process_command(841);
|
||||
// char *start_time = kdk_get_process_start_time(841);
|
||||
// printf("获取某一进程的CPU利用率:%0.1f\n", kdk_get_process_cpu_usage_percent(841));
|
||||
// printf("获取某一进程的内存占用率:%0.1f\n", kdk_get_process_mem_usage_percent(841));
|
||||
// printf("获取某一进程的进程状态:%s\n", kdk_get_process_status(841));
|
||||
// printf("获取某一进程的进程端口号:%d\n", kdk_get_process_port(841));
|
||||
// printf("获取某一进程的启动时间:%s\n", start_time);
|
||||
// printf("获取某一进程的运行时间:%s\n", run_time);
|
||||
// printf("获取某一进程的CPU时间:%s\n", cpu_time);
|
||||
// printf("获取某一进程的Command:%s\n", cmd);
|
||||
// printf("获取某一进程的属主:%s\n", kdk_get_process_user(841));
|
||||
// free(run_time);
|
||||
// free(cpu_time);
|
||||
// free(cmd);
|
||||
// free(start_time);
|
||||
// char** pid = kdk_procname_get_process_infomation("systemd");
|
||||
// size_t index = 0;
|
||||
// while (pid[index])
|
||||
// {
|
||||
// printf("pid %s\n", pid[index]);
|
||||
// index ++;
|
||||
// }
|
||||
// kdk_proc_freeall(pid);
|
||||
|
||||
char** info = kdk_get_process_all_information();
|
||||
size_t count = 0;
|
||||
|
@ -38,5 +38,13 @@ int main()
|
|||
count ++;
|
||||
}
|
||||
kdk_proc_freeall(info);
|
||||
|
||||
// char *name = kdk_get_process_name(1151571);
|
||||
// printf("name = %s\n", name);
|
||||
// free(name);
|
||||
|
||||
// int id = kdk_get_process_id("systemd");
|
||||
// printf("pid %d\n", id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -19,13 +19,13 @@ struct if_data
|
|||
|
||||
struct if_info
|
||||
{
|
||||
char ifi_name[16];
|
||||
char ifi_name[64];
|
||||
unsigned long ifi_ibytes;
|
||||
unsigned long ifi_obytes;
|
||||
};
|
||||
struct if_speed
|
||||
{
|
||||
char ifs_name[16];
|
||||
char ifs_name[64];
|
||||
unsigned long ifs_ispeed;
|
||||
unsigned long ifs_ospeed;
|
||||
unsigned long ifs_us;
|
||||
|
@ -137,6 +137,7 @@ float kdk_real_get_net_speed(const char *nc)
|
|||
if(!nc)
|
||||
return -1;
|
||||
struct if_speed ndev;
|
||||
memset(&ndev, 0, sizeof(struct if_speed));
|
||||
|
||||
int ret = 0;
|
||||
memset(&ndev, 0, sizeof(ndev));
|
||||
|
@ -231,3 +232,20 @@ int kdk_real_get_disk_rate(const char *name)
|
|||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
float kdk_real_get_if_speed(const char *nc)
|
||||
{
|
||||
if (!nc)
|
||||
return -1;
|
||||
struct if_speed ndev;
|
||||
memset(&ndev, 0, sizeof(struct if_speed));
|
||||
|
||||
int ret = 0;
|
||||
memset(&ndev, 0, sizeof(ndev));
|
||||
sprintf(ndev.ifs_name, "%s", nc);
|
||||
ndev.ifs_us = 100000;
|
||||
ret = get_if_speed(&ndev);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
return ndev.ifs_ispeed * 1.0 / (ndev.ifs_us / 1000 * 0.001) / 1024.0f;
|
||||
}
|
|
@ -1,177 +0,0 @@
|
|||
#include "libkyrealtimeinfo.h"
|
||||
#include "fcntl.h"
|
||||
#include "stdio.h"
|
||||
#include "net/if.h"
|
||||
#include "unistd.h"
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
#include "ifaddrs.h"
|
||||
#include "sys/types.h"
|
||||
#include "smartctl.h"
|
||||
using namespace KDK_SYSTEM;
|
||||
|
||||
RealTimeInfo::RealTimeInfo()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
float RealTimeInfo::kdk_real_get_io_speed()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float RealTimeInfo::kdk_real_get_net_speed()
|
||||
{
|
||||
struct if_speed ndev;
|
||||
|
||||
int ret = 0;
|
||||
memset(&ndev,0,sizeof(ndev));
|
||||
sprintf(ndev.ifs_name,"enp3s0");
|
||||
ndev.ifs_us = 100000;
|
||||
ret = get_if_speed(&ndev);
|
||||
if(ret < 0)
|
||||
return -1;
|
||||
return ndev.ifs_ospeed * 1.0/(ndev.ifs_us/1000 * 0.001) / 1024.0f;
|
||||
}
|
||||
|
||||
float RealTimeInfo::kdk_real_get_cpu_temperature()
|
||||
{
|
||||
char tmp[32] = "\0";
|
||||
char path[64] = "\0";
|
||||
for(int i = 1; i; i++)
|
||||
{
|
||||
memset(path,0,64);
|
||||
snprintf(path,64,"/sys/class/hwmon/hwmon%d",i);
|
||||
if (0 != access(path, F_OK))
|
||||
{
|
||||
snprintf(path,64,"/sys/class/hwmon/hwmon1/temp1_input");
|
||||
break;
|
||||
}
|
||||
snprintf(path,64,"/sys/class/hwmon/hwmon%d/name",i);
|
||||
if (0 != access(path, F_OK))
|
||||
continue;
|
||||
else
|
||||
snprintf(path,64,"/sys/class/hwmon/hwmon%d/temp1_input",i);
|
||||
}
|
||||
|
||||
FILE *fp = fopen(path,"r");
|
||||
if(fp)
|
||||
{
|
||||
fgets(tmp,sizeof(tmp),fp);
|
||||
fclose(fp);
|
||||
return atof(tmp) / 1000;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
float RealTimeInfo::kdk_real_get_disk_temperature(const char *name)
|
||||
{
|
||||
nvmeTemp = "";
|
||||
sataTemp = "";
|
||||
if(0 == main_worker(name))
|
||||
{
|
||||
printf("Temp %s\n",nvmeTemp.empty() ? sataTemp.c_str() : nvmeTemp.c_str());
|
||||
return atof(nvmeTemp.empty() ? sataTemp.c_str() : nvmeTemp.c_str());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int RealTimeInfo::get_if_dbytes(struct if_info *ndev)
|
||||
{
|
||||
if(!ndev)
|
||||
return -1;
|
||||
|
||||
struct ifaddrs *ifa_list = NULL;
|
||||
|
||||
struct ifaddrs *ifa = NULL;
|
||||
|
||||
struct if_data *ifd = NULL;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
ret = getifaddrs(&ifa_list);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
|
||||
perror("Get Interface Address Fail:");
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (ifa = ifa_list; ifa; ifa = ifa->ifa_next)
|
||||
{
|
||||
|
||||
if (!(ifa->ifa_flags & IFF_UP) && !(ifa->ifa_flags & IFF_RUNNING))
|
||||
|
||||
continue;
|
||||
|
||||
if (ifa->ifa_data == 0)
|
||||
|
||||
continue;
|
||||
|
||||
ret = strcmp(ifa->ifa_name, ndev->ifi_name);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
|
||||
ifd = (struct if_data *)ifa->ifa_data;
|
||||
|
||||
ndev->ifi_ibytes = ifd->ifi_ibytes;
|
||||
|
||||
ndev->ifi_obytes = ifd->ifi_obytes;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(ifa_list);
|
||||
|
||||
end:
|
||||
return (ret ? -1 : 0);
|
||||
}
|
||||
int RealTimeInfo::get_if_speed(struct if_speed *ndev)
|
||||
{
|
||||
if(!ndev)
|
||||
return -1;
|
||||
|
||||
struct if_info *p1 = NULL, *p2 = NULL;
|
||||
|
||||
p1 = (struct if_info *)malloc(sizeof(struct if_info));
|
||||
|
||||
p2 = (struct if_info *)malloc(sizeof(struct if_info));
|
||||
|
||||
bzero(p1, sizeof(struct if_info));
|
||||
|
||||
bzero(p2, sizeof(struct if_info));
|
||||
|
||||
strncpy(p1->ifi_name, ndev->ifs_name, strlen(ndev->ifs_name));
|
||||
|
||||
strncpy(p2->ifi_name, ndev->ifs_name, strlen(ndev->ifs_name));
|
||||
|
||||
int ret = 0;
|
||||
|
||||
ret = get_if_dbytes(p1);
|
||||
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
|
||||
usleep(ndev->ifs_us);
|
||||
|
||||
ret = get_if_dbytes(p2);
|
||||
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
|
||||
ndev->ifs_ispeed = p2->ifi_ibytes - p1->ifi_ibytes;
|
||||
|
||||
ndev->ifs_ospeed = p2->ifi_obytes - p1->ifi_obytes;
|
||||
|
||||
end:
|
||||
|
||||
free(p1);
|
||||
|
||||
free(p2);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -5,11 +5,45 @@
|
|||
extern "C"
|
||||
{
|
||||
#endif
|
||||
/**
|
||||
* @brief 获取瞬时网速信息
|
||||
*
|
||||
* @param nc 网卡名称,如eno1
|
||||
* @return float 瞬时网速
|
||||
*/
|
||||
extern float kdk_real_get_net_speed(const char *nc);
|
||||
|
||||
float kdk_real_get_net_speed(const char *nc);
|
||||
double kdk_real_get_cpu_temperature();
|
||||
int kdk_real_get_disk_temperature(const char *name);
|
||||
int kdk_real_get_disk_rate(const char *name);
|
||||
/**
|
||||
* @brief 获取CPU温度
|
||||
*
|
||||
*
|
||||
* @return double CPU温度
|
||||
*/
|
||||
extern double kdk_real_get_cpu_temperature();
|
||||
|
||||
/**
|
||||
* @brief 获取磁盘温度
|
||||
*
|
||||
* @param name 磁盘名称,应当是例如/dev/sda这种绝对路径
|
||||
* @return int 磁盘温度
|
||||
*/
|
||||
extern int kdk_real_get_disk_temperature(const char *name);
|
||||
|
||||
/**
|
||||
* @brief 获取磁盘转速
|
||||
*
|
||||
* @param name 磁盘名称,应当是例如/dev/sda这种绝对路径
|
||||
* @return int 磁盘转速
|
||||
*/
|
||||
extern int kdk_real_get_disk_rate(const char *name);
|
||||
|
||||
/**
|
||||
* @brief 获取下载的瞬时网速信息
|
||||
*
|
||||
* @param nc 网卡名称,如eno1
|
||||
* @return float 下载的瞬时网速
|
||||
*/
|
||||
extern float kdk_real_get_if_speed(const char *nc);
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
|
|
|
@ -1,157 +0,0 @@
|
|||
/* aacraid.h
|
||||
* Copyright (C) 2014 Raghava Aditya <Raghava.Aditya@pmcs.com>
|
||||
* Copyright (C) 2015 Nidhi Malhotra <Nidhi.Malhotra@pmcs.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
// Check windows
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#ifdef _WIN64
|
||||
#define ENVIRONMENT64
|
||||
#else
|
||||
#define ENVIRONMENT32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Check GCC
|
||||
#if __GNUC__
|
||||
#if __x86_64__ || __ppc64__
|
||||
#define ENVIRONMENT64
|
||||
#else
|
||||
#define ENVIRONMENT32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define METHOD_BUFFERED 0
|
||||
#define METHOD_NEITHER 3
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define FSAMPCTL_SCSI_BASE IOCTL_SCSI_BASE
|
||||
#define ARCIOCTL_SEND_RAW_SRB CTL_CODE(FSAMPCTL_SCSI_BASE, 2201, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define AACRAID_SAS_SIGNATURE "ARCSAS"
|
||||
#define SRB_FLAGS_DATA_IN 0x00000040
|
||||
#define SRB_FLAGS_DATA_OUT 0x00000080
|
||||
#define SRB_FLAGS_NO_DATA_TRANSFER 0x00000000
|
||||
#else
|
||||
#define CTL_CODE(function, method) ((4 << 16) | ((function) << 2) | (method))
|
||||
|
||||
#define FSACTL_SEND_RAW_SRB CTL_CODE(2067, METHOD_BUFFERED)
|
||||
#endif
|
||||
#define SRB_FUNCTION_EXECUTE_SCSI 0X00
|
||||
|
||||
#define SRB_DataIn 0x0040
|
||||
#define SRB_DataOut 0x0080
|
||||
#define SRB_NoDataXfer 0x0000
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t lo32;
|
||||
uint32_t hi32;
|
||||
} address64;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
address64 addr64;
|
||||
uint32_t length; /* Length. */
|
||||
} user_sgentry64;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t addr32;
|
||||
uint32_t length;
|
||||
} user_sgentry32;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t count;
|
||||
user_sgentry64 sg64[1];
|
||||
} user_sgmap64;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t count;
|
||||
user_sgentry32 sg32[1];
|
||||
} user_sgmap32;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
typedef struct _SCSI_REQUEST_BLOCK
|
||||
{
|
||||
USHORT Length; // offset 0
|
||||
UCHAR Function; // offset 2
|
||||
UCHAR SrbStatus; // offset 3
|
||||
UCHAR ScsiStatus; // offset 4
|
||||
UCHAR PathId; // offset 5
|
||||
UCHAR TargetId; // offset 6
|
||||
UCHAR Lun; // offset 7
|
||||
UCHAR QueueTag; // offset 8
|
||||
UCHAR QueueAction; // offset 9
|
||||
UCHAR CdbLength; // offset a
|
||||
UCHAR SenseInfoBufferLength; // offset b
|
||||
ULONG SrbFlags; // offset c
|
||||
ULONG DataTransferLength; // offset 10
|
||||
ULONG TimeOutValue; // offset 14
|
||||
PVOID DataBuffer; // offset 18
|
||||
PVOID SenseInfoBuffer; // offset 1c
|
||||
struct _SCSI_REQUEST_BLOCK *NextSrb; // offset 20
|
||||
PVOID OriginalRequest; // offset 24
|
||||
PVOID SrbExtension; // offset 28
|
||||
union
|
||||
{
|
||||
ULONG InternalStatus; // offset 2c
|
||||
ULONG QueueSortKey; // offset 2c
|
||||
};
|
||||
|
||||
#if defined(_WIN64)
|
||||
//
|
||||
// Force PVOID alignment of Cdb
|
||||
//
|
||||
ULONG Reserved;
|
||||
#endif
|
||||
|
||||
UCHAR Cdb[16]; // offset 30
|
||||
} SCSI_REQUEST_BLOCK, *PSCSI_REQUEST_BLOCK;
|
||||
|
||||
#define SCSI_REQUEST_BLOCK_SIZE sizeof(SCSI_REQUEST_BLOCK)
|
||||
|
||||
#else
|
||||
typedef struct
|
||||
{
|
||||
uint32_t function; // SRB_FUNCTION_EXECUTE_SCSI 0x00
|
||||
uint32_t channel; // bus
|
||||
uint32_t id; // use the ID number this is wrong
|
||||
uint32_t lun; // Logical unit number
|
||||
uint32_t timeout;
|
||||
uint32_t flags; // Interesting stuff I must say
|
||||
uint32_t count; // Data xfer size
|
||||
uint32_t retry_limit; // We shall see
|
||||
uint32_t cdb_size; // Length of CDB
|
||||
uint8_t cdb[16]; // The actual cdb command
|
||||
user_sgmap64 sg64; // pDatabuffer and address of Databuffer
|
||||
} user_aac_srb64;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t function; // SRB_FUNCTION_EXECUTE_SCSI 0x00
|
||||
uint32_t channel; // bus
|
||||
uint32_t id; // use the ID number this is wrong
|
||||
uint32_t lun; // Logical unit number
|
||||
uint32_t timeout;
|
||||
uint32_t flags; // Interesting stuff I must say
|
||||
uint32_t count; // Data xfer size
|
||||
uint32_t retry_limit; // We shall see
|
||||
uint32_t cdb_size; // Length of CDB
|
||||
uint8_t cdb[16]; // The actual cdb command
|
||||
user_sgmap32 sg32; // pDatabuffer and address of Databuffer
|
||||
} user_aac_srb32;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t status;
|
||||
uint32_t srb_status;
|
||||
uint32_t scsi_status;
|
||||
uint32_t data_xfer_length;
|
||||
uint32_t sense_data_size;
|
||||
uint8_t sense_data[30];
|
||||
} user_aac_reply;
|
||||
#endif
|
|
@ -1,513 +0,0 @@
|
|||
/*
|
||||
* atacmdnames.cpp
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2003-08 Philip Williams
|
||||
* Copyright (C) 2012-19 Christian Franke
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "atacmdnames.h"
|
||||
#include "static_assert.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
const char *atacmdnames_cpp_cvsid = "$Id: atacmdnames.cpp 4934 2019-07-01 20:54:14Z chrfranke $" ATACMDNAMES_H_CVSID;
|
||||
|
||||
const char cmd_reserved[] = "[RESERVED]";
|
||||
const char cmd_vendor_specific[] = "[VENDOR SPECIFIC]";
|
||||
const char cmd_reserved_sa[] = "[RESERVED FOR SERIAL ATA]";
|
||||
const char cmd_reserved_cf[] = "[RESERVED FOR COMPACTFLASH ASSOCIATION]";
|
||||
const char cmd_reserved_mcpt[] = "[RESERVED FOR MEDIA CARD PASS THROUGH]"; // ACS-3: Reserved
|
||||
const char cmd_recalibrate_ret4[] = "RECALIBRATE [RET-4]";
|
||||
const char cmd_seek_ret4[] = "SEEK [RET-4]";
|
||||
|
||||
// Tables B.3 and B.4 of T13/2161-D (ACS-3) Revision 4, September 4, 2012
|
||||
|
||||
const char *const command_table[] = {
|
||||
/*-------------------------------------------------- 00h-0Fh -----*/
|
||||
"NOP",
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
"CFA REQUEST EXTENDED ERROR",
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
"DATA SET MANAGEMENT", // ACS-2
|
||||
cmd_reserved,
|
||||
"DEVICE RESET",
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
"REQUEST SENSE DATA EXT", // ACS-2
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
/*-------------------------------------------------- 10h-1Fh -----*/
|
||||
"RECALIBRATE [OBS-4]",
|
||||
cmd_recalibrate_ret4,
|
||||
cmd_recalibrate_ret4,
|
||||
cmd_recalibrate_ret4,
|
||||
cmd_recalibrate_ret4,
|
||||
cmd_recalibrate_ret4,
|
||||
cmd_recalibrate_ret4,
|
||||
cmd_recalibrate_ret4,
|
||||
cmd_recalibrate_ret4,
|
||||
cmd_recalibrate_ret4,
|
||||
cmd_recalibrate_ret4,
|
||||
cmd_recalibrate_ret4,
|
||||
cmd_recalibrate_ret4,
|
||||
cmd_recalibrate_ret4,
|
||||
cmd_recalibrate_ret4,
|
||||
cmd_recalibrate_ret4,
|
||||
/*-------------------------------------------------- 20h-2Fh -----*/
|
||||
"READ SECTOR(S)",
|
||||
"READ SECTOR(S) [OBS-5]",
|
||||
"READ LONG [OBS-4]",
|
||||
"READ LONG (w/o retry) [OBS-4]",
|
||||
"READ SECTOR(S) EXT",
|
||||
"READ DMA EXT",
|
||||
"READ DMA QUEUED EXT [OBS-ACS-2]",
|
||||
"READ NATIVE MAX ADDRESS EXT [OBS-ACS-3]",
|
||||
cmd_reserved,
|
||||
"READ MULTIPLE EXT",
|
||||
"READ STREAM DMA",
|
||||
"READ STREAM",
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
"READ LOG EXT",
|
||||
/*-------------------------------------------------- 30h-3Fh -----*/
|
||||
"WRITE SECTOR(S)",
|
||||
"WRITE SECTOR(S) (w/o retry) [OBS-5]",
|
||||
"WRITE LONG [OBS-4]",
|
||||
"WRITE LONG (w/o retry) [OBS-4]",
|
||||
"WRITE SECTORS(S) EXT",
|
||||
"WRITE DMA EXT",
|
||||
"WRITE DMA QUEUED EXT [OBS-ACS-2]",
|
||||
"SET NATIVE MAX ADDRESS EXT [OBS-ACS-3]",
|
||||
"CFA WRITE SECTORS WITHOUT ERASE",
|
||||
"WRITE MULTIPLE EXT",
|
||||
"WRITE STREAM DMA",
|
||||
"WRITE STREAM",
|
||||
"WRITE VERIFY [OBS-4]",
|
||||
"WRITE DMA FUA EXT",
|
||||
"WRITE DMA QUEUED FUA EXT [OBS-ACS-2]",
|
||||
"WRITE LOG EXT",
|
||||
/*-------------------------------------------------- 40h-4Fh -----*/
|
||||
"READ VERIFY SECTOR(S)",
|
||||
"READ VERIFY SECTOR(S) (w/o retry) [OBS-5]",
|
||||
"READ VERIFY SECTOR(S) EXT",
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
"WRITE UNCORRECTABLE EXT", // ATA-8
|
||||
cmd_reserved,
|
||||
"READ LOG DMA EXT", // ATA-8
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
/*-------------------------------------------------- 50h-5Fh -----*/
|
||||
"FORMAT TRACK [OBS-4]",
|
||||
"CONFIGURE STREAM",
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
"WRITE LOG DMA EXT", // ATA-8
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
"TRUSTED NON-DATA", // ATA-8
|
||||
"TRUSTED RECEIVE", // ATA-8
|
||||
"TRUSTED RECEIVE DMA", // ATA-8
|
||||
"TRUSTED SEND", // ATA-8
|
||||
"TRUSTED SEND DMA", // ATA-8
|
||||
/*-------------------------------------------------- 60h-6Fh -----*/
|
||||
"READ FPDMA QUEUED", // ATA-8
|
||||
"WRITE FPDMA QUEUED", // ATA-8
|
||||
cmd_reserved_sa,
|
||||
"NCQ QUEUE MANAGEMENT", // ACS-3
|
||||
"SEND FPDMA QUEUED", // ACS-3
|
||||
"RECEIVE FPDMA QUEUED", // ACS-3
|
||||
cmd_reserved_sa,
|
||||
cmd_reserved_sa,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
/*-------------------------------------------------- 70h-7Fh -----*/
|
||||
"SEEK [OBS-7]",
|
||||
cmd_seek_ret4,
|
||||
cmd_seek_ret4,
|
||||
cmd_seek_ret4,
|
||||
cmd_seek_ret4,
|
||||
cmd_seek_ret4,
|
||||
cmd_seek_ret4,
|
||||
"SET DATE & TIME EXT", // ACS-3
|
||||
"ACCESSIBLE MAX ADDRESS CONFIGURATION", // ACS-3
|
||||
cmd_seek_ret4,
|
||||
cmd_seek_ret4,
|
||||
cmd_seek_ret4,
|
||||
cmd_seek_ret4,
|
||||
cmd_seek_ret4,
|
||||
cmd_seek_ret4,
|
||||
cmd_seek_ret4,
|
||||
/*-------------------------------------------------- 80h-8Fh -----*/
|
||||
cmd_vendor_specific,
|
||||
cmd_vendor_specific,
|
||||
cmd_vendor_specific,
|
||||
cmd_vendor_specific,
|
||||
cmd_vendor_specific,
|
||||
cmd_vendor_specific,
|
||||
cmd_vendor_specific,
|
||||
"CFA TRANSLATE SECTOR [VS IF NO CFA]",
|
||||
cmd_vendor_specific,
|
||||
cmd_vendor_specific,
|
||||
cmd_vendor_specific,
|
||||
cmd_vendor_specific,
|
||||
cmd_vendor_specific,
|
||||
cmd_vendor_specific,
|
||||
cmd_vendor_specific,
|
||||
cmd_vendor_specific,
|
||||
/*-------------------------------------------------- 90h-9Fh -----*/
|
||||
"EXECUTE DEVICE DIAGNOSTIC",
|
||||
"INITIALIZE DEVICE PARAMETERS [OBS-6]",
|
||||
"DOWNLOAD MICROCODE",
|
||||
"DOWNLOAD MICROCODE DMA", // ACS-2
|
||||
"STANDBY IMMEDIATE [RET-4]",
|
||||
"IDLE IMMEDIATE [RET-4]",
|
||||
"STANDBY [RET-4]",
|
||||
"IDLE [RET-4]",
|
||||
"CHECK POWER MODE [RET-4]",
|
||||
"SLEEP [RET-4]",
|
||||
cmd_vendor_specific,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
/*-------------------------------------------------- A0h-AFh -----*/
|
||||
"PACKET",
|
||||
"IDENTIFY PACKET DEVICE",
|
||||
"SERVICE [OBS-ACS-2]",
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
/*-------------------------------------------------- B0h-BFh -----*/
|
||||
"SMART",
|
||||
"DEVICE CONFIGURATION [OBS-ACS-3]",
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
"SANITIZE DEVICE", // ACS-2
|
||||
cmd_reserved,
|
||||
"NV CACHE [OBS-ACS-3]", // ATA-8
|
||||
cmd_reserved_cf,
|
||||
cmd_reserved_cf,
|
||||
cmd_reserved_cf,
|
||||
cmd_reserved_cf,
|
||||
cmd_reserved_cf,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
/*-------------------------------------------------- C0h-CFh -----*/
|
||||
"CFA ERASE SECTORS [VS IF NO CFA]",
|
||||
cmd_vendor_specific,
|
||||
cmd_vendor_specific,
|
||||
cmd_vendor_specific,
|
||||
"READ MULTIPLE",
|
||||
"WRITE MULTIPLE",
|
||||
"SET MULTIPLE MODE",
|
||||
"READ DMA QUEUED [OBS-ACS-2]",
|
||||
"READ DMA",
|
||||
"READ DMA (w/o retry) [OBS-5]",
|
||||
"WRITE DMA",
|
||||
"WRITE DMA (w/o retry) [OBS-5]",
|
||||
"WRITE DMA QUEUED [OBS-ACS-2]",
|
||||
"CFA WRITE MULTIPLE WITHOUT ERASE",
|
||||
"WRITE MULTIPLE FUA EXT",
|
||||
cmd_reserved,
|
||||
/*-------------------------------------------------- D0h-DFh -----*/
|
||||
cmd_reserved,
|
||||
"CHECK MEDIA CARD TYPE [OBS-ACS-2]",
|
||||
cmd_reserved_mcpt,
|
||||
cmd_reserved_mcpt,
|
||||
cmd_reserved_mcpt,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
cmd_reserved,
|
||||
"GET MEDIA STATUS [OBS-8]",
|
||||
"ACKNOWLEDGE MEDIA CHANGE [RET-4]",
|
||||
"BOOT POST-BOOT [RET-4]",
|
||||
"BOOT PRE-BOOT [RET-4]",
|
||||
"MEDIA LOCK [OBS-8]",
|
||||
"MEDIA UNLOCK [OBS-8]",
|
||||
/*-------------------------------------------------- E0h-EFh -----*/
|
||||
"STANDBY IMMEDIATE",
|
||||
"IDLE IMMEDIATE",
|
||||
"STANDBY",
|
||||
"IDLE",
|
||||
"READ BUFFER",
|
||||
"CHECK POWER MODE",
|
||||
"SLEEP",
|
||||
"FLUSH CACHE",
|
||||
"WRITE BUFFER",
|
||||
"READ BUFFER DMA", // ACS-2 (was: WRITE SAME [RET-4])
|
||||
"FLUSH CACHE EXT",
|
||||
"WRITE BUFFER DMA", // ACS-2
|
||||
"IDENTIFY DEVICE",
|
||||
"MEDIA EJECT [OBS-8]",
|
||||
"IDENTIFY DEVICE DMA [OBS-4]",
|
||||
"SET FEATURES",
|
||||
/*-------------------------------------------------- F0h-FFh -----*/
|
||||
cmd_vendor_specific,
|
||||
"SECURITY SET PASSWORD",
|
||||
"SECURITY UNLOCK",
|
||||
"SECURITY ERASE PREPARE",
|
||||
"SECURITY ERASE UNIT",
|
||||
"SECURITY FREEZE LOCK",
|
||||
"SECURITY DISABLE PASSWORD",
|
||||
cmd_vendor_specific,
|
||||
"READ NATIVE MAX ADDRESS [OBS-ACS-3]",
|
||||
"SET MAX ADDRESS [OBS-ACS-3]",
|
||||
cmd_vendor_specific,
|
||||
cmd_vendor_specific,
|
||||
cmd_vendor_specific,
|
||||
cmd_vendor_specific,
|
||||
cmd_vendor_specific,
|
||||
cmd_vendor_specific};
|
||||
|
||||
STATIC_ASSERT(sizeof(command_table) == 256 * sizeof(command_table[0]));
|
||||
|
||||
/* Returns the name of the command (and possibly sub-command) with the given
|
||||
command code and feature register values. For most command codes this
|
||||
simply returns the corresponding entry in the command_table array, but for
|
||||
others the value of the feature register specifies a subcommand or
|
||||
distinguishes commands. */
|
||||
const char *look_up_ata_command(unsigned char c_code, unsigned char f_reg)
|
||||
{
|
||||
|
||||
switch (c_code)
|
||||
{
|
||||
case 0x00: /* NOP */
|
||||
switch (f_reg)
|
||||
{
|
||||
case 0x00:
|
||||
return "NOP [Abort queued commands]";
|
||||
case 0x01:
|
||||
return "NOP [Don't abort queued commands] [OBS-ACS-2]";
|
||||
default:
|
||||
return "NOP [Reserved subcommand] [OBS-ACS-2]";
|
||||
}
|
||||
case 0x92: /* DOWNLOAD MICROCODE */
|
||||
switch (f_reg)
|
||||
{
|
||||
case 0x01:
|
||||
return "DOWNLOAD MICROCODE [Temporary] [OBS-8]";
|
||||
case 0x03:
|
||||
return "DOWNLOAD MICROCODE [Save with offsets]"; // ATA-8
|
||||
case 0x07:
|
||||
return "DOWNLOAD MICROCODE [Save]";
|
||||
case 0x0e:
|
||||
return "DOWNLOAD MICROCODE [Save for future use]"; // ACS-3
|
||||
case 0x0f:
|
||||
return "DOWNLOAD MICROCODE [Activate]"; // ACS-3
|
||||
default:
|
||||
return "DOWNLOAD MICROCODE [Reserved subcommand]";
|
||||
}
|
||||
case 0xB0: /* SMART */
|
||||
switch (f_reg)
|
||||
{
|
||||
case 0xD0:
|
||||
return "SMART READ DATA";
|
||||
case 0xD1:
|
||||
return "SMART READ ATTRIBUTE THRESHOLDS [OBS-4]";
|
||||
case 0xD2:
|
||||
return "SMART ENABLE/DISABLE ATTRIBUTE AUTOSAVE";
|
||||
case 0xD3:
|
||||
return "SMART SAVE ATTRIBUTE VALUES [OBS-6]";
|
||||
case 0xD4:
|
||||
return "SMART EXECUTE OFF-LINE IMMEDIATE";
|
||||
case 0xD5:
|
||||
return "SMART READ LOG";
|
||||
case 0xD6:
|
||||
return "SMART WRITE LOG";
|
||||
case 0xD7:
|
||||
return "SMART WRITE ATTRIBUTE THRESHOLDS [NS, OBS-4]";
|
||||
case 0xD8:
|
||||
return "SMART ENABLE OPERATIONS";
|
||||
case 0xD9:
|
||||
return "SMART DISABLE OPERATIONS";
|
||||
case 0xDA:
|
||||
return "SMART RETURN STATUS";
|
||||
case 0xDB:
|
||||
return "SMART EN/DISABLE AUTO OFFLINE [NS (SFF-8035i)]";
|
||||
default:
|
||||
if (f_reg >= 0xE0)
|
||||
return "SMART [Vendor specific subcommand]";
|
||||
else
|
||||
return "SMART [Reserved subcommand]";
|
||||
}
|
||||
case 0xB1: /* DEVICE CONFIGURATION */
|
||||
switch (f_reg)
|
||||
{
|
||||
case 0xC0:
|
||||
return "DEVICE CONFIGURATION RESTORE [OBS-ACS-3]";
|
||||
case 0xC1:
|
||||
return "DEVICE CONFIGURATION FREEZE LOCK [OBS-ACS-3]";
|
||||
case 0xC2:
|
||||
return "DEVICE CONFIGURATION IDENTIFY [OBS-ACS-3]";
|
||||
case 0xC3:
|
||||
return "DEVICE CONFIGURATION SET [OBS-ACS-3]";
|
||||
default:
|
||||
return "DEVICE CONFIGURATION [Reserved subcommand] [OBS-ACS-3]";
|
||||
}
|
||||
case 0xEF: /* SET FEATURES */
|
||||
switch (f_reg)
|
||||
{
|
||||
case 0x01:
|
||||
return "SET FEATURES [Enable 8-bit PIO] [OBS-3]"; // Now CFA
|
||||
case 0x02:
|
||||
return "SET FEATURES [Enable write cache]";
|
||||
case 0x03:
|
||||
return "SET FEATURES [Set transfer mode]";
|
||||
case 0x04:
|
||||
return "SET FEATURES [Enable auto DR] [OBS-4]";
|
||||
case 0x05:
|
||||
return "SET FEATURES [Enable APM]";
|
||||
case 0x06:
|
||||
return "SET FEATURES [Enable Pwr-Up In Standby]";
|
||||
case 0x07:
|
||||
return "SET FEATURES [Set device spin-up]";
|
||||
case 0x09:
|
||||
return "SET FEATURES [Reserved (address offset)] [OPS-ACS-3]";
|
||||
case 0x0A:
|
||||
return "SET FEATURES [Enable CFA power mode 1]";
|
||||
case 0x10:
|
||||
return "SET FEATURES [Enable SATA feature]"; // ACS-3
|
||||
case 0x20:
|
||||
return "SET FEATURES [Set Time-ltd R/W WCT]";
|
||||
case 0x21:
|
||||
return "SET FEATURES [Set Time-ltd R/W EH]";
|
||||
case 0x31:
|
||||
return "SET FEATURES [Disable Media Status Notf] [OBS-8]";
|
||||
case 0x33:
|
||||
return "SET FEATURES [Disable retry] [OBS-4]";
|
||||
case 0x41:
|
||||
return "SET FEATURES [Enable Free-fall Control]"; // ATA-8
|
||||
case 0x42:
|
||||
return "SET FEATURES [Enable AAM] [OBS-ACS-2]";
|
||||
case 0x43:
|
||||
return "SET FEATURES [Set Max Host I/F S Times]";
|
||||
case 0x44:
|
||||
return "SET FEATURES [Length of VS data] [OBS-4]";
|
||||
case 0x4a:
|
||||
return "SET FEATURES [Ext. Power Conditions]"; // ACS-2
|
||||
case 0x54:
|
||||
return "SET FEATURES [Set cache segs] [OBS-4]";
|
||||
case 0x55:
|
||||
return "SET FEATURES [Disable read look-ahead]";
|
||||
case 0x5D:
|
||||
return "SET FEATURES [Enable release interrupt] [OBS-ACS-2]";
|
||||
case 0x5E:
|
||||
return "SET FEATURES [Enable SERVICE interrupt] [OBS-ACS-2]";
|
||||
case 0x66:
|
||||
return "SET FEATURES [Disable revert defaults]";
|
||||
case 0x69:
|
||||
return "SET FEATURES [LPS Error Reporting Control]"; // ACS-2
|
||||
case 0x77:
|
||||
return "SET FEATURES [Disable ECC] [OBS-4]";
|
||||
case 0x81:
|
||||
return "SET FEATURES [Disable 8-bit PIO] [OBS-3]"; // Now CFA
|
||||
case 0x82:
|
||||
return "SET FEATURES [Disable write cache]";
|
||||
case 0x84:
|
||||
return "SET FEATURES [Disable auto DR] [OBS-4]";
|
||||
case 0x85:
|
||||
return "SET FEATURES [Disable APM]";
|
||||
case 0x86:
|
||||
return "SET FEATURES [Disable Pwr-Up In Standby]";
|
||||
case 0x88:
|
||||
return "SET FEATURES [Disable ECC] [OBS-4]";
|
||||
case 0x89:
|
||||
return "SET FEATURES [Reserved (address offset)]";
|
||||
case 0x8A:
|
||||
return "SET FEATURES [Disable CFA power mode 1]";
|
||||
case 0x90:
|
||||
return "SET FEATURES [Disable SATA feature]"; // ACS-3
|
||||
case 0x95:
|
||||
return "SET FEATURES [Enable Media Status Notf] [OBS-8]";
|
||||
case 0x99:
|
||||
return "SET FEATURES [Enable retries] [OBS-4]";
|
||||
case 0x9A:
|
||||
return "SET FEATURES [Set max avg curr] [OBS-4]";
|
||||
case 0xAA:
|
||||
return "SET FEATURES [Enable read look-ahead]";
|
||||
case 0xAB:
|
||||
return "SET FEATURES [Set max prefetch] [OBS-4]";
|
||||
case 0xBB:
|
||||
return "SET FEATURES [4 bytes VS data] [OBS-4]";
|
||||
case 0xC1:
|
||||
return "SET FEATURES [Disable Free-fall Control]"; // ATA-8
|
||||
case 0xC2:
|
||||
return "SET FEATURES [Disable AAM] [OBS-ACS-2]";
|
||||
case 0xC3:
|
||||
return "SET FEATURES [Sense Data Reporting]"; // ACS-2
|
||||
case 0xCC:
|
||||
return "SET FEATURES [Enable revert to defaults]";
|
||||
case 0xDD:
|
||||
return "SET FEATURES [Disable release interrupt] [OBS-ACS-2]";
|
||||
case 0xDE:
|
||||
return "SET FEATURES [Disable SERVICE interrupt] [OBS-ACS-2]";
|
||||
case 0xE0:
|
||||
return "SET FEATURES [Vendor specific] [OBS-7]";
|
||||
default:
|
||||
if (f_reg >= 0xF0)
|
||||
return "SET FEATURES [Reserved for CFA]";
|
||||
else
|
||||
return "SET FEATURES [Reserved subcommand]";
|
||||
}
|
||||
case 0xF9: /* SET MAX */
|
||||
switch (f_reg)
|
||||
{
|
||||
case 0x00:
|
||||
return "SET MAX ADDRESS [OBS-6]";
|
||||
case 0x01:
|
||||
return "SET MAX SET PASSWORD [OBS-ACS-3]";
|
||||
case 0x02:
|
||||
return "SET MAX LOCK [OBS-ACS-3]";
|
||||
case 0x03:
|
||||
return "SET MAX UNLOCK [OBS-ACS-3]";
|
||||
case 0x04:
|
||||
return "SET MAX FREEZE LOCK [OBS-ACS-3]";
|
||||
default:
|
||||
return "SET MAX [Reserved subcommand] [OBS-ACS-3]";
|
||||
}
|
||||
default:
|
||||
return command_table[c_code];
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
/*
|
||||
* atacmdnames.h
|
||||
*
|
||||
* This module is based on the T13/1532D Volume 1 Revision 3 (ATA/ATAPI-7)
|
||||
* specification, which is available from http://www.t13.org/#FTP_site
|
||||
*
|
||||
* Home page of code is: http://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2003-8 Philip Williams
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef ATACMDNAMES_H_
|
||||
#define ATACMDNAMES_H_
|
||||
|
||||
#define ATACMDNAMES_H_CVSID "$Id: atacmdnames.h 4760 2018-08-19 18:45:53Z chrfranke $\n"
|
||||
|
||||
/* Returns the name of the command (and possibly sub-command) with the given
|
||||
command code and feature register values. */
|
||||
const char *look_up_ata_command(unsigned char c_code, unsigned char f_reg);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,757 +0,0 @@
|
|||
/*
|
||||
* ataidentify.cpp
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2012-21 Christian Franke
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#define __STDC_FORMAT_MACROS 1 // enable PRI* for C++
|
||||
|
||||
#include "ataidentify.h"
|
||||
|
||||
const char *ataidentify_cpp_cvsid = "$Id: ataidentify.cpp 5227 2021-06-26 15:20:41Z chrfranke $" ATAIDENTIFY_H_CVSID;
|
||||
|
||||
#include "utility.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
// Table 12 of X3T10/0948D (ATA-2) Revision 4c, March 18, 1996
|
||||
// Table 9 of X3T13/2008D (ATA-3) Revision 7b, January 27, 1997
|
||||
// Tables 11 and 13 of T13/1153D (ATA/ATAPI-4) revision 18, August 19, 1998
|
||||
// Tables 20 and 22 of T13/1321D (ATA/ATAPI-5) Revision 3, February 29, 2000
|
||||
// Tables 27 and 29 of T13/1410D (ATA/ATAPI-6) Revision 3b, February 26, 2002
|
||||
// Tables 16 and 18 of T13/1532D (ATA/ATAPI-7) Volume 1 Revision 4b, April 21, 2004
|
||||
// Tables 29 and 39 of T13/1699-D (ATA8-ACS) Revision 6a, September 6, 2008
|
||||
// Tables 50 and 61 of T13/2015-D (ACS-2) Revision 7, June 22, 2011
|
||||
// Tables 45 and 50 of T13/2161-D (ACS-3) Revision 5, October 28, 2013
|
||||
// Table 55 of T13/BSR INCITS 529 (ACS-4) Revision 20, October 26, 2017 (ATAPI removed)
|
||||
// Table 57 of T13/BSR INCITS 558 (ACS-5) Revision 10, March 3, 2021
|
||||
|
||||
const char *const identify_descriptions[] = {
|
||||
" 0 General configuration",
|
||||
". 15 Device identifier: 0 = ATA, 1 = ATAPI",
|
||||
". 14:8 ATA: Vendor specific [RET-3]",
|
||||
". 14 ATAPI: Must be set to 0",
|
||||
". 13 ATAPI: Reserved",
|
||||
". 12:8 ATAPI: Command set: 0x05 = CD/DVD",
|
||||
". 7 Removable media device [OBS-8]",
|
||||
". 6 ATA: Not removable controller and/or device [OBS-6]",
|
||||
". 5:3 ATA: Vendor specific [RET-3]",
|
||||
". 6:5 ATAPI: DRQ after PACKET cmd: 0x0 = 3ms, 0x2 = 50us",
|
||||
". 4:3 ATAPI: Reserved",
|
||||
". 2 Response incomplete",
|
||||
". 1 ATA: Vendor specific [RET-3]",
|
||||
". 0 ATA: Reserved",
|
||||
". 1:0 ATAPI: Packet size: 0x0 = 12 byte, 0x1 = 16 byte",
|
||||
|
||||
" 1 Cylinders [OBS-6]",
|
||||
" 2 Specific configuration (0x37c8/738c/8c73/c837)",
|
||||
" 3 Heads [OBS-6]",
|
||||
" 4 Vendor specific [RET-3]",
|
||||
" 5 Vendor specific [RET-3]",
|
||||
" 6 Sectors per track [OBS-6]",
|
||||
" 7-8 Reserved for CFA (Sectors per card)",
|
||||
" 9 Vendor specific [RET-4]",
|
||||
" 10-19 Serial number (String)",
|
||||
" 20 Vendor specific [RET-3]",
|
||||
" 21 Vendor specific [RET-3]",
|
||||
" 22 Vendor specific bytes on READ/WRITE LONG [OBS-4]",
|
||||
" 23-26 Firmware revision (String)",
|
||||
" 27-46 Model number (String)",
|
||||
|
||||
" 47 READ/WRITE MULTIPLE support",
|
||||
". 15:8 Must be set to 0x80",
|
||||
". 7:0 Maximum sectors per DRQ on READ/WRITE MULTIPLE",
|
||||
|
||||
" 48 Trusted Computing feature set options",
|
||||
". 15:14 Must be set to 0x1",
|
||||
". 13:1 Reserved for the Trusted Computing Group",
|
||||
". 0 Trusted Computing feature set supported",
|
||||
|
||||
" 49 Capabilities",
|
||||
". 15:14 ATA: Reserved for IDENTIFY PACKET DEVICE",
|
||||
". 15 ATAPI: Interleaved DMA supported [OBS-8]",
|
||||
". 14 ATAPI: Command queuing supported [OBS-8]",
|
||||
". 13 ATA: Standard standby timer values supported",
|
||||
". 13 ATAPI: Overlap operation supported [OBS-8]",
|
||||
". 12 ATA: Reserved for IDENTIFY PACKET DEVICE",
|
||||
". 12 ATAPI: ATA software reset required [OBS-5]",
|
||||
". 11 IORDY supported",
|
||||
". 10 IORDY may be disabled",
|
||||
". 9 LBA supported",
|
||||
". 8 DMA supported",
|
||||
". 7:2 Reserved", // ATA-3: Vendor specific, ATA-8: Retired
|
||||
". 1:0 Long Phy Sector Alignment Error reporting", // ACS-2
|
||||
|
||||
" 50 Capabilities",
|
||||
". 15:14 Must be set to 0x1",
|
||||
". 13:2 Reserved",
|
||||
". 1 Reserved [OBS-6]",
|
||||
". 0 Vendor specific minimum standby timer value",
|
||||
|
||||
" 51 PIO data transfer mode [OBS-5]",
|
||||
" 52 Single Word DMA data transfer mode [OBS-3]",
|
||||
|
||||
" 53 Field validity / Free-fall Control",
|
||||
". 15:8 Free-fall Control sensitivity",
|
||||
". 7:3 Reserved",
|
||||
". 2 Word 88 (Ultra DMA modes) is valid",
|
||||
". 1 Words 64-70 (PIO modes) are valid",
|
||||
". 0 Words 54-58 (CHS) are valid [OBS-6]",
|
||||
|
||||
" 54 Current cylinders [OBS-6]",
|
||||
" 55 Current heads [OBS-6]",
|
||||
" 56 Current sectors per track [OBS-6]",
|
||||
" 57-58 Current capacity in sectors (DWord) [OBS-6]",
|
||||
|
||||
" 59 Sanitize Device - READ/WRITE MULTIPLE support",
|
||||
". 15 BLOCK ERASE EXT supported",
|
||||
". 14 OVERWRITE EXT supported",
|
||||
". 13 CRYPTO SCRAMBLE EXT supported",
|
||||
". 12 Sanitize Device feature set supported",
|
||||
". 11 Cmds during sanitize are as specified by ACS-3", // ACS-3
|
||||
". 10 SANITIZE ANTIFREEZE LOCK EXT supported", // ACS-3
|
||||
". 9 Reserved",
|
||||
". 8 Bits 7:0 are valid [OBS-ACS-4]",
|
||||
". 7:0 Current number of sectors per DRQ [OBS-ACS-4]",
|
||||
|
||||
" 60-61 User addressable sectors for 28-bit commands (DWord)",
|
||||
" 62 Single Word DMA modes [OBS-3]",
|
||||
|
||||
" 63 Multiword DMA modes",
|
||||
". 15:11 Reserved",
|
||||
". 10 Multiword DMA mode 2 selected",
|
||||
". 9 Multiword DMA mode 1 selected",
|
||||
". 8 Multiword DMA mode 0 selected",
|
||||
". 7:3 Reserved",
|
||||
". 2 Multiword DMA mode 2 and below supported",
|
||||
". 1 Multiword DMA mode 1 and below supported",
|
||||
". 0 Multiword DMA mode 0 supported",
|
||||
|
||||
" 64 PIO modes",
|
||||
". 15:2 Reserved",
|
||||
". 1 PIO mode 4 supported",
|
||||
". 0 PIO mode 3 supported",
|
||||
|
||||
" 65 Minimum Multiword DMA cycle time per word in ns",
|
||||
" 66 Recommended Multiword DMA cycle time in ns",
|
||||
" 67 Minimum PIO cycle time without flow control in ns",
|
||||
" 68 Minimum PIO cycle time with IORDY flow control in ns",
|
||||
|
||||
" 69 Additional support",
|
||||
". 15 CFast specification supported",
|
||||
". 14 Deterministic data after trim supported",
|
||||
". 13 LPS Alignment Error Reporting Control supported",
|
||||
". 12 DCO IDENTIFY/SET DMA supported [OBS-ACS-3]",
|
||||
". 11 READ BUFFER DMA supported",
|
||||
". 10 WRITE BUFFER DMA supported",
|
||||
". 9 SET MAX SET PASSWORD/UNLOCK DMA supported [OBS-ACS-3]",
|
||||
". 8 DOWNLOAD MICROCODE DMA supported",
|
||||
". 7 Reserved for IEEE 1667",
|
||||
". 6 Optional ATA device 28-bit commands supported",
|
||||
". 5 Trimmed LBA range(s) returning zeroed data supported",
|
||||
". 4 Device encrypts all user data",
|
||||
". 3 Extended number of user addressable sectors supported",
|
||||
". 2 All write cache is non-volatile", // ACS-3
|
||||
". 1:0 Zoned Capabilities [OBS-ACS-5]", // ACS-4
|
||||
|
||||
" 70 Reserved",
|
||||
" 71-74 ATA: Reserved for IDENTIFY PACKET DEVICE",
|
||||
" 71 ATAPI: Time in ns from PACKET to bus release [OBS-8]",
|
||||
" 72 ATAPI: Time in ns from SERVICE to BSY cleared [OBS-8]",
|
||||
" 73-74 ATAPI: Reserved",
|
||||
|
||||
" 75 Queue depth",
|
||||
". 15:5 Reserved",
|
||||
". 4:0 Maximum queue depth - 1",
|
||||
|
||||
" 76 Serial ATA capabilities",
|
||||
". 15 READ LOG DMA EXT as equiv to READ LOG EXT supported",
|
||||
". 14 Device Auto Partial to Slumber transitions supported",
|
||||
". 13 Host Auto Partial to Slumber transitions supported",
|
||||
". 12 NCQ priority information supported",
|
||||
". 11 Unload while NCQ commands are outstanding supported",
|
||||
". 10 Phy Event Counters supported",
|
||||
". 9 Receipt of host initiated PM requests supported",
|
||||
". 8 NCQ feature set supported",
|
||||
". 7:4 Reserved for Serial ATA",
|
||||
". 3 SATA Gen3 signaling speed (6.0 Gb/s) supported",
|
||||
". 2 SATA Gen2 signaling speed (3.0 Gb/s) supported",
|
||||
". 1 SATA Gen1 signaling speed (1.5 Gb/s) supported",
|
||||
". 0 Must be set to 0",
|
||||
|
||||
" 77 Serial ATA additional capabilities", // ACS-3
|
||||
". 15:10 Reserved for Serial ATA",
|
||||
". 9 Out Of Band Management supported", // ACS-5
|
||||
". 8 Power Disable feature always enabled", // ACS-4
|
||||
". 7 DevSleep to ReducedPwrState supported", // ACS-4
|
||||
". 6 RECEIVE/SEND FPDMA QUEUED supported",
|
||||
". 5 NCQ Queue Management supported",
|
||||
". 4 NCQ Streaming supported",
|
||||
". 3:1 Current Serial ATA signal speed",
|
||||
". 0 Must be set to 0",
|
||||
|
||||
" 78 Serial ATA features supported",
|
||||
". 15:13 Reserved for Serial ATA",
|
||||
". 12 Power Disable feature supported", // ACS-4
|
||||
". 11 Rebuild Assist feature set supported", // ACS-4
|
||||
". 10 Reserved for Serial ATA",
|
||||
". 9 Hybrid Information supported", // ACS-4
|
||||
". 8 Device Sleep feature supported", // ACS-4
|
||||
". 7 NCQ Autosense supported", // ACS-3
|
||||
". 6 Software Settings Preservation supported",
|
||||
". 5 Hardware Feature Control supported", // ACS-3
|
||||
". 4 In-order data delivery supported",
|
||||
". 3 Device initiated power management supported",
|
||||
". 2 DMA Setup auto-activation supported",
|
||||
". 1 Non-zero buffer offsets supported",
|
||||
". 0 Must be set to 0",
|
||||
|
||||
" 79 Serial ATA features enabled",
|
||||
". 15:12 Reserved for Serial ATA",
|
||||
". 11 Rebuild Assist feature set enabled", // ACS-4
|
||||
". 10 Power Disable feature enabled", // ACS-4
|
||||
". 9 Hybrid Information enabled", // ACS-4
|
||||
". 8 Device Sleep feature enabled", // ACS-4
|
||||
". 7 Automatic Partial to Slumber transitions enabled", // ACS-3
|
||||
". 6 Software Settings Preservation enabled",
|
||||
". 5 Hardware Feature Control enabled", // ACS-3
|
||||
". 4 In-order data delivery enabled",
|
||||
". 3 Device initiated power management enabled",
|
||||
". 2 DMA Setup auto-activation enabled",
|
||||
". 1 Non-zero buffer offsets enabled",
|
||||
". 0 Must be set to 0",
|
||||
|
||||
" 80 Major version number",
|
||||
". 15:13 Reserved",
|
||||
". 12 ACS-5 supported",
|
||||
". 11 ACS-4 supported",
|
||||
". 10 ACS-3 supported",
|
||||
". 9 ACS-2 supported",
|
||||
". 8 ATA8-ACS supported",
|
||||
". 7 ATA/ATAPI-7 supported [OBS-ACS-4]",
|
||||
". 6 ATA/ATAPI-6 supported [OBS-ACS-4]",
|
||||
". 5 ATA/ATAPI-5 supported [OBS-ACS-4]",
|
||||
". 4 ATA/ATAPI-4 supported [OBS-8]",
|
||||
". 3 ATA-3 supported [OBS-7]",
|
||||
". 2 ATA-2 supported [OBS-6]",
|
||||
". 1 ATA-1 supported [OBS-5]",
|
||||
". 0 Reserved",
|
||||
|
||||
" 81 Minor version number",
|
||||
|
||||
" 82 Commands and feature sets supported",
|
||||
". 15 IDENTIFY DEVICE DMA supported [OBS-4]", // ATA-4 r07-r14 only
|
||||
". 14 NOP supported",
|
||||
". 13 READ BUFFER supported",
|
||||
". 12 WRITE BUFFER supported",
|
||||
". 11 WRITE VERIFY supported [OBS-4]", // ATA-4 r07-r13 only
|
||||
". 10 HPA feature set supported [OBS-ACS-3]",
|
||||
". 9 DEVICE RESET supported", // ATA:0, ATAPI:1
|
||||
". 8 SERVICE interrupt supported [OBS-ACS-2]",
|
||||
". 7 Release interrupt supported [OBS-ACS-2]",
|
||||
". 6 Read look-ahead supported",
|
||||
". 5 Volatile write cache supported",
|
||||
". 4 PACKET feature set supported", // ATA:0, ATAPI:1
|
||||
". 3 Power Management feature set supported",
|
||||
". 2 Removable Media feature set supported [OBS-8]",
|
||||
". 1 Security feature set supported",
|
||||
". 0 SMART feature set supported",
|
||||
|
||||
" 83 Commands and feature sets supported",
|
||||
". 15:14 Must be set to 0x1",
|
||||
". 13 FLUSH CACHE EXT supported",
|
||||
". 12 FLUSH CACHE supported",
|
||||
". 11 DCO feature set supported [OBS-ACS-3]",
|
||||
". 10 48-bit Address feature set supported",
|
||||
". 9 AAM feature set supported [OBS-ACS-2]",
|
||||
". 8 SET MAX security extension supported [OBS-ACS-3]",
|
||||
". 7 Reserved for Addr Offset Resvd Area Boot [OBS-ACS-3]",
|
||||
". 6 SET FEATURES subcommand required to spin-up",
|
||||
". 5 PUIS feature set supported",
|
||||
". 4 Removable Media Status Notification supported [OBS-8]",
|
||||
". 3 APM feature set supported",
|
||||
". 2 CFA feature set supported",
|
||||
". 1 TCQ feature set supported [OBS-ACS-2]",
|
||||
". 0 DOWNLOAD MICROCODE supported",
|
||||
|
||||
" 84 Commands and feature sets supported",
|
||||
". 15:14 Must be set to 0x1",
|
||||
". 13 IDLE IMMEDIATE with UNLOAD feature supported",
|
||||
". 12:11 Reserved for TLC [OBS-ACS-3]",
|
||||
". 10 URG bit for WRITE STREAM (DMA) EXT supported [OBS-8]",
|
||||
". 9 URG bit for READ STREAM (DMA) EXT supported [OBS-8]",
|
||||
". 8 64-bit World Wide Name supported",
|
||||
". 7 WRITE DMA QUEUED FUA EXT supported [OBS-ACS-2]",
|
||||
". 6 WRITE DMA/MULTIPLE FUA EXT supported",
|
||||
". 5 GPL feature set supported",
|
||||
". 4 Streaming feature set supported",
|
||||
". 3 Media Card Pass Through Command supported [OBS-ACS-2]",
|
||||
". 2 Media serial number supported [RES-ACS-3]",
|
||||
". 1 SMART self-test supported",
|
||||
". 0 SMART error logging supported",
|
||||
|
||||
" 85 Commands and feature sets supported or enabled",
|
||||
". 15 IDENTIFY DEVICE DMA supported [OBS-4]", // ATA-4 r07-r14 only
|
||||
". 14 NOP supported",
|
||||
". 13 READ BUFFER supported",
|
||||
". 12 WRITE BUFFER supported",
|
||||
". 11 WRITE VERIFY supported [OBS-4]", // ATA-4 r07-r13 only
|
||||
". 10 HPA feature set supported [OBS-ACS-3]",
|
||||
". 9 DEVICE RESET supported", // ATA:0, ATAPI:1
|
||||
". 8 SERVICE interrupt enabled [OBS-ACS-2]",
|
||||
". 7 Release interrupt enabled [OBS-ACS-2]",
|
||||
". 6 Read look-ahead enabled",
|
||||
". 5 Write cache enabled",
|
||||
". 4 PACKET feature set supported", // ATA:0, ATAPI:1
|
||||
". 3 Power Management feature set supported",
|
||||
". 2 Removable Media feature set supported [OBS-8]",
|
||||
". 1 Security feature set enabled",
|
||||
". 0 SMART feature set enabled",
|
||||
|
||||
" 86 Commands and feature sets supported or enabled",
|
||||
". 15 Words 119-120 are valid",
|
||||
". 14 Reserved",
|
||||
". 13 FLUSH CACHE EXT supported",
|
||||
". 12 FLUSH CACHE supported",
|
||||
". 11 DCO feature set supported [OBS-ACS-3]",
|
||||
". 10 48-bit Address features set supported",
|
||||
". 9 AAM feature set enabled [OBS-ACS-2]",
|
||||
". 8 SET MAX security extension enabled [OBS-ACS-3]",
|
||||
". 7 Reserved for Addr Offset Resvd Area Boot [OBS-ACS-3]",
|
||||
". 6 SET FEATURES subcommand required to spin-up",
|
||||
". 5 PUIS feature set enabled",
|
||||
". 4 Removable Media Status Notification enabled [OBS-8]",
|
||||
". 3 APM feature set enabled",
|
||||
". 2 CFA feature set supported",
|
||||
". 1 TCQ feature set supported [OBS-ACS-2]",
|
||||
". 0 DOWNLOAD MICROCODE supported",
|
||||
|
||||
" 87 Commands and feature sets supported or enabled",
|
||||
". 15:14 Must be set to 0x1",
|
||||
". 13 IDLE IMMEDIATE with UNLOAD FEATURE supported",
|
||||
". 12:11 Reserved for TLC [OBS-ACS-3]",
|
||||
". 10 URG bit for WRITE STREAM (DMA) EXT supported [OBS-8]",
|
||||
". 9 URG bit for READ STREAM (DMA) EXT supported [OBS-8]",
|
||||
". 8 64-bit World Wide Name supported",
|
||||
". 7 WRITE DMA QUEUED FUA EXT supported [OBS-ACS-2]",
|
||||
". 6 WRITE DMA/MULTIPLE FUA EXT supported",
|
||||
". 5 GPL feature set supported",
|
||||
". 4 Valid CONFIGURE STREAM has been executed [OBS-8]",
|
||||
". 3 Media Card Pass Through Command supported [OBS-ACS-2]",
|
||||
". 2 Media serial number is valid",
|
||||
". 1 SMART self-test supported",
|
||||
". 0 SMART error logging supported",
|
||||
|
||||
" 88 Ultra DMA modes",
|
||||
". 15 Reserved",
|
||||
". 14 Ultra DMA mode 6 selected",
|
||||
". 13 Ultra DMA mode 5 selected",
|
||||
". 12 Ultra DMA mode 4 selected",
|
||||
". 11 Ultra DMA mode 3 selected",
|
||||
". 10 Ultra DMA mode 2 selected",
|
||||
". 9 Ultra DMA mode 1 selected",
|
||||
". 8 Ultra DMA mode 0 selected",
|
||||
". 7 Reserved",
|
||||
". 6 Ultra DMA mode 6 and below supported",
|
||||
". 5 Ultra DMA mode 5 and below supported",
|
||||
". 4 Ultra DMA mode 4 and below supported",
|
||||
". 3 Ultra DMA mode 3 and below supported",
|
||||
". 2 Ultra DMA mode 2 and below supported",
|
||||
". 1 Ultra DMA mode 1 and below supported",
|
||||
". 0 Ultra DMA mode 0 supported",
|
||||
|
||||
" 89 SECURITY ERASE UNIT time",
|
||||
". 15 Bits 14:8 of value are valid", // ACS-3
|
||||
". 14:0 SECURITY ERASE UNIT time value", // value*2 minutes
|
||||
|
||||
" 90 ENHANCED SECURITY ERASE UNIT time",
|
||||
". 15 Bits 14:8 of value are valid", // ACS-3
|
||||
". 14:0 ENHANCED SECURITY ERASE UNIT time value", // value*2 minutes
|
||||
|
||||
" 91 Current APM level",
|
||||
". 15:8 Reserved", // ACS-3
|
||||
". 7:0 Current APM level value",
|
||||
|
||||
" 92 Master Password Identifier", // ATA-7: Master Password Revision Code
|
||||
|
||||
" 93 Hardware reset result (PATA)",
|
||||
". 15:14 Must be set to 0x1",
|
||||
". 13 Device detected CBLID- above(1)/below(0) ViHB",
|
||||
". 12 Reserved",
|
||||
". 11 Device 1 asserted PDIAG-",
|
||||
". 10:9 Device 1 detection method: -, Jumper, CSEL, other",
|
||||
". 8 Must be set to 1",
|
||||
". 7 Reserved",
|
||||
". 6 Device 0 responds when device 1 selected",
|
||||
". 5 Device 0 detected the assertion of DASP-",
|
||||
". 4 Device 0 detected the assertion of PDIAG-",
|
||||
". 3 Device 0 passed diagnostics",
|
||||
". 2:1 Device 0 detection method: -, Jumper, CSEL, other",
|
||||
". 0 Must be set to 1 for PATA devices",
|
||||
|
||||
" 94 AAM level [OBS-ACS-2]",
|
||||
". 15:8 Recommended AAM level [OBS-ACS-2]",
|
||||
". 7:0 Current AAM level [OBS-ACS-2]",
|
||||
|
||||
" 95 Stream Minimum Request Size",
|
||||
" 96 Streaming Transfer Time - DMA",
|
||||
" 97 Streaming Access Latency - DMA and PIO",
|
||||
" 98-99 Streaming Performance Granularity (DWord)",
|
||||
"100-103 User addressable sectors for 48-bit commands (QWord)",
|
||||
"104 Streaming Transfer Time - PIO",
|
||||
"105 Max blocks of LBA Range Entries per DS MANAGEMENT cmd",
|
||||
|
||||
"106 Physical sector size / logical sector size",
|
||||
". 15:14 Must be set to 0x1",
|
||||
". 13 Multiple logical sectors per physical sector",
|
||||
". 12 Logical Sector longer than 256 words",
|
||||
". 11:4 Reserved",
|
||||
". 3:0 2^X logical sectors per physical sector",
|
||||
|
||||
"107 Inter-seek delay for ISO 7779 acoustic testing",
|
||||
"108-111 World Wide Name",
|
||||
"112-115 Reserved", // ATA-7: Reserved for world wide name extension to 128 bits
|
||||
"116 Reserved for TLC [OBS-ACS-3]",
|
||||
"117-118 Logical sector size (DWord)",
|
||||
|
||||
"119 Commands and feature sets supported",
|
||||
". 15:14 Must be set to 0x1",
|
||||
". 13:10 Reserved",
|
||||
". 9 DSN feature set supported", // ACS-3
|
||||
". 8 Accessible Max Address Config feature set supported", // ACS-3
|
||||
". 7 Extended Power Conditions feature set supported",
|
||||
". 6 Sense Data Reporting feature set supported",
|
||||
". 5 Free-fall Control feature set supported",
|
||||
". 4 DOWNLOAD MICROCODE with mode 3 supported",
|
||||
". 3 READ/WRITE LOG DMA EXT supported",
|
||||
". 2 WRITE UNCORRECTABLE EXT supported",
|
||||
". 1 Write-Read-Verify feature set supported",
|
||||
". 0 Reserved for DDT [OBS-ACS-3]",
|
||||
|
||||
"120 Commands and feature sets supported or enabled",
|
||||
". 15:14 Must be set to 0x1",
|
||||
". 13:10 Reserved",
|
||||
". 9 DSN feature set enabled", // ACS-3
|
||||
". 8 Reserved",
|
||||
". 7 Extended Power Conditions feature set enabled",
|
||||
". 6 Sense Data Reporting feature set enabled",
|
||||
". 5 Free-fall Control feature set enabled",
|
||||
". 4 DOWNLOAD MICROCODE with mode 3 supported",
|
||||
". 3 READ/WRITE LOG DMA EXT supported",
|
||||
". 2 WRITE UNCORRECTABLE EXT supported",
|
||||
". 1 Write-Read-Verify feature set enabled",
|
||||
". 0 Reserved for DDT [OBS-ACS-3]",
|
||||
|
||||
"121-126 ATA: Reserved",
|
||||
"121-124 ATAPI: Reserved",
|
||||
"125 ATAPI: Byte count = 0 behavior",
|
||||
"126 ATAPI: Byte count = 0 behavior [OBS-6]",
|
||||
|
||||
"127 Removable Media Status Notification [OBS-8]",
|
||||
". 15:1 Reserved",
|
||||
". 0 Removable Media Status Notification supported",
|
||||
|
||||
"128 Security status",
|
||||
". 15:9 Reserved",
|
||||
". 8 Master password capability: 0 = High, 1 = Maximum",
|
||||
". 7:6 Reserved",
|
||||
". 5 Enhanced security erase supported",
|
||||
". 4 Security count expired",
|
||||
". 3 Security frozen",
|
||||
". 2 Security locked",
|
||||
". 1 Security enabled",
|
||||
". 0 Security supported",
|
||||
|
||||
"129-159 Vendor specific",
|
||||
|
||||
"160 CFA power mode",
|
||||
// ". 15 Word 160 supported",
|
||||
// ". 14 Reserved",
|
||||
// ". 13 CFA power mode 1 is required for some commands",
|
||||
// ". 12 CFA power mode 1 disabled",
|
||||
// ". 11:0 Maximum current in mA",
|
||||
"161-167 Reserved for CFA",
|
||||
|
||||
"168 Form factor",
|
||||
". 15:4 Reserved",
|
||||
". 3:0 Nominal form factor: -, 5.25, 3.5, 2.5, 1.8, ...", // <1.8, ACS-4: mSATA, M.2, ...
|
||||
|
||||
"169 DATA SET MANAGEMENT command support",
|
||||
". 15:1 Reserved",
|
||||
". 0 Trim bit in DATA SET MANAGEMENT command supported",
|
||||
|
||||
"170-173 Additional product identifier (String)",
|
||||
"174-175 Reserved",
|
||||
"176-205 Current media serial number (String)",
|
||||
|
||||
"206 SCT Command Transport",
|
||||
". 15:12 Vendor specific",
|
||||
". 11:8 Reserved",
|
||||
". 7 Reserved for Serial ATA",
|
||||
". 6 Reserved",
|
||||
". 5 SCT Data Tables supported",
|
||||
". 4 SCT Feature Control supported",
|
||||
". 3 SCT Error Recovery Control supported",
|
||||
". 2 SCT Write Same supported",
|
||||
". 1 SCT Read/Write Long supported [OBS-ACS-2]",
|
||||
". 0 SCT Command Transport supported",
|
||||
|
||||
"207-208 Reserved", // ATA-8: Reserved for CE-ATA
|
||||
|
||||
"209 Alignment of logical sectors",
|
||||
". 15:14 Must be set to 0x1",
|
||||
". 13:0 Logical sector offset",
|
||||
|
||||
"210-211 Write-Read-Verify sector count mode 3 (DWord)",
|
||||
"212-213 Write-Read-Verify sector count mode 2 (DWord)",
|
||||
|
||||
"214 NV Cache capabilities [OBS-ACS-3]",
|
||||
". 15:12 NV Cache feature set version [OBS-ACS-3]",
|
||||
". 11:8 NV Cache Power Mode feature set version [OBS-ACS-3]",
|
||||
". 7:5 Reserved [OBS-ACS-3]",
|
||||
". 4 NV Cache feature set enabled [OBS-ACS-3]",
|
||||
". 3:2 Reserved",
|
||||
". 1 NV Cache Power Mode feature set enabled [OBS-ACS-3]",
|
||||
". 0 NV Cache Power Mode feature set supported [OBS-ACS-3]",
|
||||
|
||||
"215-216 NV Cache size in logical blocks (DWord) [OBS-ACS-3]",
|
||||
"217 Nominal media rotation rate",
|
||||
"218 Reserved",
|
||||
|
||||
"219 NV Cache options [OBS-ACS-3]",
|
||||
". 15:8 Reserved [OBS-ACS-3]",
|
||||
". 7:0 Estimated time to spin up in seconds [OBS-ACS-3]",
|
||||
|
||||
"220 Write-Read-Verify mode",
|
||||
". 15:8 Reserved",
|
||||
". 7:0 Write-Read-Verify feature set current mode",
|
||||
|
||||
"221 Reserved",
|
||||
|
||||
"222 Transport major version number",
|
||||
". 15:12 Transport: 0x0 = Parallel, 0x1 = Serial, 0xe = PCIe", // PCIe: ACS-4
|
||||
". 11 Reserved | Reserved",
|
||||
". 10 Reserved | SATA 3.5", // ACS-5
|
||||
". 9 Reserved | SATA 3.4", // ACS-5
|
||||
". 8 Reserved | SATA 3.3", // ACS-4
|
||||
". 7 Reserved | SATA 3.2", // ACS-4
|
||||
". 6 Reserved | SATA 3.1", // ACS-3
|
||||
". 5 Reserved | SATA 3.0", // ACS-2
|
||||
". 4 Reserved | SATA 2.6",
|
||||
". 3 Reserved | SATA 2.5",
|
||||
". 2 Reserved | SATA II: Extensions",
|
||||
". 1 ATA/ATAPI-7 | SATA 1.0a",
|
||||
". 0 ATA8-APT | ATA8-AST",
|
||||
|
||||
"223 Transport minor version number",
|
||||
"224-229 Reserved",
|
||||
"230-233 Extended number of user addressable sectors (QWord)",
|
||||
"234 Minimum blocks per DOWNLOAD MICROCODE mode 3 command",
|
||||
"235 Maximum blocks per DOWNLOAD MICROCODE mode 3 command",
|
||||
"236-254 Reserved",
|
||||
|
||||
"255 Integrity word",
|
||||
". 15:8 Checksum",
|
||||
". 7:0 Signature"};
|
||||
|
||||
const int num_identify_descriptions = sizeof(identify_descriptions) / sizeof(identify_descriptions[0]);
|
||||
|
||||
static inline unsigned short get_word(const void *id, int word)
|
||||
{
|
||||
const unsigned char *p = ((const unsigned char *)id) + 2 * word;
|
||||
return p[0] + (p[1] << 8);
|
||||
}
|
||||
|
||||
void ata_print_identify_data(const void *id, bool all_words, int bit_level)
|
||||
{
|
||||
// ATA or ATAPI ?
|
||||
unsigned short w = get_word(id, 0);
|
||||
bool is_atapi = ((w & 0x8000) && (w != 0x848a /*CompactFlash Signature*/));
|
||||
|
||||
int prev_word = -1, prev_bit = -1;
|
||||
pout("Word %s Value Description\n", (bit_level >= 0 ? "Bit " : " "));
|
||||
|
||||
for (int i = 0; i < num_identify_descriptions; i++)
|
||||
{
|
||||
// Parse table entry
|
||||
const char *desc = identify_descriptions[i];
|
||||
|
||||
int word = prev_word, word2 = -1;
|
||||
int bit = -1, bit2 = -1;
|
||||
|
||||
int nc;
|
||||
unsigned v1, v2;
|
||||
if (word >= 0 && sscanf(desc, ". %u:%u %n", &v1, &v2, (nc = -1, &nc)) == 2 && nc > 0 && 16 > v1 && v1 > v2)
|
||||
{
|
||||
bit = v1;
|
||||
bit2 = v2;
|
||||
}
|
||||
else if (word >= 0 && sscanf(desc, ". %u %n", &v1, (nc = -1, &nc)) == 1 && nc > 0 && v1 < 16)
|
||||
{
|
||||
bit = v1;
|
||||
}
|
||||
else if (sscanf(desc, "%u-%u %n", &v1, &v2, (nc = -1, &nc)) == 2 && nc > 0 && v1 < v2 && v2 < 256)
|
||||
{
|
||||
word = v1, word2 = v2;
|
||||
}
|
||||
else if (sscanf(desc, "%u %n", &v1, (nc = -1, &nc)) == 1 && nc > 0 && v1 < 256)
|
||||
{
|
||||
word = v1;
|
||||
}
|
||||
else
|
||||
{
|
||||
pout("Error: #%d: Syntax\n", i);
|
||||
continue;
|
||||
}
|
||||
desc += nc;
|
||||
|
||||
// Check for ATA/ATAPI specific entries
|
||||
if (str_starts_with(desc, "ATA: "))
|
||||
{
|
||||
if (is_atapi)
|
||||
continue;
|
||||
desc += sizeof("ATA: ") - 1;
|
||||
}
|
||||
else if (str_starts_with(desc, "ATAPI: "))
|
||||
{
|
||||
if (!is_atapi)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check table entry
|
||||
if (bit < 0)
|
||||
{
|
||||
if (word != prev_word + 1)
|
||||
{
|
||||
pout("Error: #%d: Missing word %d\n", i, prev_word + 1);
|
||||
return;
|
||||
}
|
||||
else if (prev_bit > 0)
|
||||
{
|
||||
pout("Error: #%d: Missing bit 0 from word %d\n", i, prev_word);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (!((prev_bit < 0 && bit == 15) || bit == prev_bit - 1))
|
||||
{
|
||||
pout("Error: #%d: Missing bit %d from word %d\n", i, bit + 1, word);
|
||||
return;
|
||||
}
|
||||
|
||||
w = get_word(id, word);
|
||||
bool w_is_set = (w != 0x0000 && w != 0xffff);
|
||||
|
||||
if (bit >= 0)
|
||||
{
|
||||
int b;
|
||||
if (bit2 >= 0)
|
||||
b = (w >> bit2) & ~(~0U << (bit - bit2 + 1));
|
||||
else
|
||||
b = (w >> bit) & 1;
|
||||
|
||||
if ((bit_level >= 0 && b) || (bit_level >= 1 && w_is_set) || (bit_level >= 2 && all_words))
|
||||
{
|
||||
if (bit2 >= 0)
|
||||
{
|
||||
// Print bitfield
|
||||
char valstr[20];
|
||||
snprintf(valstr, sizeof(valstr), "0x%0*x", (bit - bit2 + 4) >> 2, b);
|
||||
pout("%4d %2d:%-2d %6s %s\n", word, bit, bit2, valstr, desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Print bit
|
||||
pout("%4d %2d %u %s\n", word, bit, b, desc);
|
||||
}
|
||||
}
|
||||
|
||||
prev_bit = (bit2 >= 0 ? bit2 : bit);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (word2 >= 0)
|
||||
{
|
||||
for (int j = word + 1; !w_is_set && j <= word2; j++)
|
||||
{
|
||||
if (get_word(id, j) != w)
|
||||
w_is_set = true;
|
||||
}
|
||||
|
||||
// Print word array
|
||||
if (all_words || w_is_set)
|
||||
{
|
||||
pout("%s%4d-%-3d %s",
|
||||
(bit_level >= 0 ? "\n" : ""), word, word2,
|
||||
(bit_level >= 0 ? "- " : ""));
|
||||
|
||||
if (!w_is_set)
|
||||
{
|
||||
pout("0x%02x... %s\n", w & 0xff, desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool is_str = !!strstr(desc, "(String)");
|
||||
pout(". %s", desc);
|
||||
|
||||
for (int j = word; j <= word2; j += 4)
|
||||
{
|
||||
if (j + 2 * 4 < word2 && !nonempty((const unsigned char *)id + 2 * j, 2 * (word2 - j + 1)))
|
||||
{
|
||||
// Remaining words are null
|
||||
pout("\n%4d-%-3d %s0x0000:0000:0000:00...", j, word2,
|
||||
(bit_level >= 0 ? ". " : ""));
|
||||
break;
|
||||
}
|
||||
// Print 4 words in a row
|
||||
pout("\n%4d-%-3d %s0x", j, (j + 3 <= word2 ? j + 3 : word2),
|
||||
(bit_level >= 0 ? ". " : ""));
|
||||
int k;
|
||||
for (k = 0; k < 4 && j + k <= word2; k++)
|
||||
pout("%s%04x", (k == 0 ? "" : ":"), get_word(id, j + k));
|
||||
|
||||
if (is_str)
|
||||
{
|
||||
// Append little endian string
|
||||
pout("%*s \"", 20 - 5 * k, "");
|
||||
for (k = 0; k < 4 && j + k <= word2; k++)
|
||||
{
|
||||
char c2 = ((const char *)id)[2 * (j + k)];
|
||||
char c1 = ((const char *)id)[2 * (j + k) + 1];
|
||||
pout("%c%c", (' ' <= c1 && c1 <= '~' ? c1 : '.'),
|
||||
(' ' <= c2 && c2 <= '~' ? c2 : '.'));
|
||||
}
|
||||
pout("\"");
|
||||
}
|
||||
}
|
||||
|
||||
// Print decimal value of D/QWords
|
||||
if (word + 1 == word2 && strstr(desc, "(DWord)"))
|
||||
pout(" (%u)\n", ((unsigned)get_word(id, word2) << 16) | w);
|
||||
else if (word + 3 == word2 && strstr(desc, "(QWord)"))
|
||||
pout(" (%" PRIu64 ")\n", ((uint64_t)get_word(id, word + 3) << 48) | ((uint64_t)get_word(id, word + 2) << 32) | ((unsigned)get_word(id, word + 1) << 16) | (unsigned)w);
|
||||
else
|
||||
pout("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Print word
|
||||
if (all_words || w_is_set)
|
||||
pout("%s%4d %s0x%04x %s\n",
|
||||
(bit_level >= 0 ? "\n" : ""), word,
|
||||
(bit_level >= 0 ? "- " : ""), w, desc);
|
||||
}
|
||||
|
||||
prev_word = (word2 >= 0 ? word2 : word);
|
||||
prev_bit = -1;
|
||||
}
|
||||
}
|
||||
|
||||
pout("\n");
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
* ataidentify.h
|
||||
*
|
||||
* Home page of code is: http://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2012 Christian Franke
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef ATAIDENTIFY_H
|
||||
#define ATAIDENTIFY_H
|
||||
|
||||
#define ATAIDENTIFY_H_CVSID "$Id: ataidentify.h 4760 2018-08-19 18:45:53Z chrfranke $"
|
||||
|
||||
void ata_print_identify_data(const void *id, bool all_words, int bit_level);
|
||||
|
||||
#endif // ATAIDENTIFY_H
|
File diff suppressed because it is too large
Load Diff
|
@ -1,114 +0,0 @@
|
|||
/*
|
||||
* ataprint.h
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2002-09 Bruce Allen
|
||||
* Copyright (C) 2008-21 Christian Franke
|
||||
* Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef ATAPRINT_H_
|
||||
#define ATAPRINT_H_
|
||||
|
||||
#define ATAPRINT_H_CVSID "$Id: ataprint.h 5192 2021-02-01 17:26:52Z chrfranke $\n"
|
||||
|
||||
#include <vector>
|
||||
|
||||
// Request to dump a GP or SMART log
|
||||
struct ata_log_request
|
||||
{
|
||||
bool gpl = false; // false: SMART, true: GP
|
||||
unsigned char logaddr = 0; // Log address
|
||||
unsigned page = 0; // First page (sector)
|
||||
unsigned nsectors = 0; // # Sectors
|
||||
};
|
||||
|
||||
// Options for ataPrintMain
|
||||
struct ata_print_options
|
||||
{
|
||||
bool drive_info = false;
|
||||
int identify_word_level = -1, identify_bit_level = -1;
|
||||
bool smart_check_status = false;
|
||||
bool smart_general_values = false;
|
||||
bool smart_vendor_attrib = false;
|
||||
bool smart_error_log = false;
|
||||
bool smart_selftest_log = false;
|
||||
bool smart_selective_selftest_log = false;
|
||||
|
||||
bool gp_logdir = false, smart_logdir = false;
|
||||
unsigned smart_ext_error_log = 0;
|
||||
unsigned smart_ext_selftest_log = 0;
|
||||
bool retry_error_log = false, retry_selftest_log = false;
|
||||
|
||||
std::vector<ata_log_request> log_requests;
|
||||
|
||||
bool devstat_all_pages = false, devstat_ssd_page = false;
|
||||
std::vector<int> devstat_pages;
|
||||
|
||||
unsigned pending_defects_log = 0;
|
||||
|
||||
bool sct_temp_sts = false, sct_temp_hist = false;
|
||||
int sct_erc_get = 0; // get(1), get_power_on(2)
|
||||
int sct_erc_set = 0; // set(1), set_power_on(2), mfg_default(3)
|
||||
unsigned sct_erc_readtime = 0, sct_erc_writetime = 0;
|
||||
bool sataphy = false, sataphy_reset = false;
|
||||
|
||||
bool smart_disable = false, smart_enable = false;
|
||||
bool smart_auto_offl_disable = false, smart_auto_offl_enable = false;
|
||||
bool smart_auto_save_disable = false, smart_auto_save_enable = false;
|
||||
|
||||
int smart_selftest_type = -1; // OFFLINE_FULL_SCAN, ..., see atacmds.h. -1 for no test
|
||||
bool smart_selftest_force = false; // Ignore already running test
|
||||
ata_selective_selftest_args smart_selective_args; // Extra args for selective self-test
|
||||
|
||||
unsigned sct_temp_int = 0;
|
||||
bool sct_temp_int_pers = false;
|
||||
|
||||
enum
|
||||
{
|
||||
FMT_BRIEF = 0x01,
|
||||
FMT_HEX_ID = 0x02,
|
||||
FMT_HEX_VAL = 0x04
|
||||
};
|
||||
unsigned char output_format = 0; // FMT_* flags
|
||||
|
||||
firmwarebug_defs firmwarebugs; // -F options
|
||||
bool fix_swapped_id = false; // Fix swapped ID strings returned by some buggy drivers
|
||||
|
||||
ata_vendor_attr_defs attribute_defs; // -v options
|
||||
|
||||
bool ignore_presets = false; // Ignore presets from drive database
|
||||
bool show_presets = false; // Show presets and exit
|
||||
unsigned char powermode = 0; // Skip check, if disk in idle or standby mode
|
||||
unsigned char powerexit = 0; // exit() code for low power mode
|
||||
int powerexit_unsup = -1; // exit() code for unsupported power mode or -1 to ignore
|
||||
|
||||
bool get_set_used = false; // true if any get/set command is used
|
||||
bool get_aam = false; // print Automatic Acoustic Management status
|
||||
int set_aam = 0; // disable(-1), enable(1..255->0..254) Automatic Acoustic Management
|
||||
bool get_apm = false; // print Advanced Power Management status
|
||||
int set_apm = 0; // disable(-1), enable(2..255->1..254) Advanced Power Management
|
||||
bool get_lookahead = false; // print read look-ahead status
|
||||
int set_lookahead = 0; // disable(-1), enable(1) read look-ahead
|
||||
int set_standby = 0; // set(1..255->0..254) standby timer
|
||||
bool set_standby_now = false; // set drive to standby
|
||||
bool get_security = false; // print ATA security status
|
||||
bool set_security_freeze = false; // Freeze ATA security
|
||||
bool get_wcache = false; // print write cache status
|
||||
int set_wcache = 0; // disable(-1), enable(1) write cache
|
||||
bool sct_wcache_reorder_get = false; // print write cache reordering status
|
||||
int sct_wcache_reorder_set = 0; // disable(-1), enable(1) write cache reordering
|
||||
bool sct_wcache_reorder_set_pers = false;
|
||||
bool sct_wcache_sct_get = false; // print SCT Feature Control of write cache status
|
||||
int sct_wcache_sct_set = 0; // determined by ata set features command(1), force enable(2), force disable(3)
|
||||
bool sct_wcache_sct_set_pers = false; // persistent or volatile
|
||||
bool get_dsn = false; // print DSN status
|
||||
int set_dsn = 0; // disable(02h), enable(01h) DSN
|
||||
};
|
||||
|
||||
int ataPrintMain(ata_device *device, const ata_print_options &options);
|
||||
|
||||
#endif
|
|
@ -1,251 +0,0 @@
|
|||
/*
|
||||
* cciss.cpp
|
||||
*
|
||||
* Home page of code is: http://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2007 Sergey Svishchev
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined(linux) || defined(__linux__)
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef HAVE_LINUX_COMPILER_H
|
||||
#include <linux/compiler.h>
|
||||
#endif
|
||||
#if defined(HAVE_LINUX_CCISS_IOCTL_H)
|
||||
#include <linux/cciss_ioctl.h>
|
||||
#define _HAVE_CCISS
|
||||
#endif
|
||||
#include <asm/byteorder.h>
|
||||
#ifndef be32toh
|
||||
#define be32toh __be32_to_cpu
|
||||
#endif
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#include <sys/endian.h>
|
||||
#include CISS_LOCATION
|
||||
#define _HAVE_CCISS
|
||||
#endif
|
||||
|
||||
#ifdef _HAVE_CCISS
|
||||
#include "cciss.h"
|
||||
#include "scsicmds.h"
|
||||
#include "utility.h"
|
||||
|
||||
const char *cciss_cpp_cvsid = "$Id: cciss.cpp 4977 2019-11-22 19:57:04Z chrfranke $" CCISS_H_CVSID;
|
||||
|
||||
typedef struct _ReportLUNdata_struct
|
||||
{
|
||||
uint32_t LUNListLength; /* always big-endian */
|
||||
uint32_t reserved;
|
||||
uint8_t LUN[CISS_MAX_LUN][8];
|
||||
} ReportLunData_struct;
|
||||
|
||||
/* Structure/defines of Report Physical LUNS of drive */
|
||||
#ifndef CISS_MAX_LUN
|
||||
#define CISS_MAX_LUN 16
|
||||
#endif
|
||||
#define CISS_MAX_PHYS_LUN 1024
|
||||
#define CISS_REPORT_PHYS 0xc3
|
||||
|
||||
#define LSCSI_DRIVER_SENSE 0x8 /* alternate CHECK CONDITION indication */
|
||||
#define SEND_IOCTL_RESP_SENSE_LEN 16 /* ioctl limitation */
|
||||
|
||||
static int cciss_getlun(int device, int target, unsigned char *physlun, int report);
|
||||
static int cciss_sendpassthru(unsigned int cmdtype, unsigned char *CDB,
|
||||
unsigned int CDBlen, char *buff,
|
||||
unsigned int size, unsigned int LunID,
|
||||
unsigned char *scsi3addr, int fd);
|
||||
|
||||
/*
|
||||
This is an interface that uses the cciss passthrough to talk to the SMART controller on
|
||||
the HP system. The cciss driver provides a way to send SCSI cmds through the CCISS passthrough.
|
||||
*/
|
||||
int cciss_io_interface(int device, int target, struct scsi_cmnd_io *iop, int report)
|
||||
{
|
||||
switch (iop->dxfer_dir)
|
||||
{
|
||||
case DXFER_NONE:
|
||||
case DXFER_FROM_DEVICE:
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP; // TODO: Support DXFER_TO_DEVICE
|
||||
}
|
||||
|
||||
unsigned char phylun[8] = {0};
|
||||
|
||||
int status = cciss_getlun(device, target, phylun, report);
|
||||
if (report > 0)
|
||||
pout(" cciss_getlun(%d, %d) = 0x%x; scsi3addr: %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
device, target, status,
|
||||
phylun[0], phylun[1], phylun[2], phylun[3], phylun[4], phylun[5], phylun[6], phylun[7]);
|
||||
if (status)
|
||||
{
|
||||
return -ENXIO; /* give up, assume no device there */
|
||||
}
|
||||
|
||||
unsigned char sensebuf[SEND_IOCTL_RESP_SENSE_LEN];
|
||||
unsigned char *pBuf = (iop->dxferp ? iop->dxferp : sensebuf);
|
||||
unsigned iBufLen = (iop->dxferp ? iop->dxfer_len : sizeof(sensebuf));
|
||||
|
||||
status = cciss_sendpassthru(2, iop->cmnd, iop->cmnd_len, (char *)pBuf, iBufLen, 1, phylun, device);
|
||||
|
||||
if (0 == status)
|
||||
{
|
||||
if (report > 0)
|
||||
pout(" status=0\n");
|
||||
if (DXFER_FROM_DEVICE == iop->dxfer_dir)
|
||||
{
|
||||
if (report > 1)
|
||||
{
|
||||
int trunc = (iop->dxfer_len > 256) ? 1 : 0;
|
||||
pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
|
||||
(trunc ? " [only first 256 bytes shown]" : ""));
|
||||
dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len), 1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
iop->scsi_status = status & 0x7e; /* bits 0 and 7 used to be for vendors */
|
||||
if (LSCSI_DRIVER_SENSE == ((status >> 24) & 0xf))
|
||||
iop->scsi_status = SCSI_STATUS_CHECK_CONDITION;
|
||||
unsigned len = (SEND_IOCTL_RESP_SENSE_LEN < iop->max_sense_len) ? SEND_IOCTL_RESP_SENSE_LEN : iop->max_sense_len;
|
||||
if (len > iBufLen)
|
||||
len = iBufLen;
|
||||
if ((SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) &&
|
||||
iop->sensep && (len > 0))
|
||||
{
|
||||
memcpy(iop->sensep, pBuf, len);
|
||||
iop->resp_sense_len = len;
|
||||
if (report > 1)
|
||||
{
|
||||
pout(" >>> Sense buffer, len=%d:\n", (int)len);
|
||||
dStrHex((const uint8_t *)pBuf, len, 1);
|
||||
}
|
||||
}
|
||||
if (report)
|
||||
{
|
||||
if (SCSI_STATUS_CHECK_CONDITION == iop->scsi_status)
|
||||
{
|
||||
pout(" status=%x: sense_key=%x asc=%x ascq=%x\n", status & 0xff,
|
||||
pBuf[2] & 0xf, pBuf[12], pBuf[13]);
|
||||
}
|
||||
else
|
||||
pout(" status=0x%x\n", status);
|
||||
}
|
||||
if (iop->scsi_status > 0)
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
if (report > 0)
|
||||
pout(" ioctl status=0x%x but scsi status=0, fail with ENXIO\n", status);
|
||||
return -ENXIO; /* give up, assume no device there */
|
||||
}
|
||||
}
|
||||
|
||||
static int cciss_sendpassthru(unsigned int cmdtype, unsigned char *CDB,
|
||||
unsigned int CDBlen, char *buff,
|
||||
unsigned int size, unsigned int LunID,
|
||||
unsigned char *scsi3addr, int fd)
|
||||
{
|
||||
int err;
|
||||
IOCTL_Command_struct iocommand;
|
||||
|
||||
memset(&iocommand, 0, sizeof(iocommand));
|
||||
|
||||
if (cmdtype == 0)
|
||||
{
|
||||
// To controller; nothing to do
|
||||
}
|
||||
else if (cmdtype == 1)
|
||||
{
|
||||
iocommand.LUN_info.LogDev.VolId = LunID;
|
||||
iocommand.LUN_info.LogDev.Mode = 1;
|
||||
}
|
||||
else if (cmdtype == 2)
|
||||
{
|
||||
memcpy(&iocommand.LUN_info.LunAddrBytes, scsi3addr, 8);
|
||||
iocommand.LUN_info.LogDev.Mode = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pout("cciss_sendpassthru: bad cmdtype\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
memcpy(&iocommand.Request.CDB[0], CDB, CDBlen);
|
||||
iocommand.Request.CDBLen = CDBlen;
|
||||
iocommand.Request.Type.Type = TYPE_CMD;
|
||||
iocommand.Request.Type.Attribute = ATTR_SIMPLE;
|
||||
iocommand.Request.Type.Direction = XFER_READ; // TODO: OK for DXFER_NONE ?
|
||||
iocommand.Request.Timeout = 0;
|
||||
|
||||
iocommand.buf_size = size;
|
||||
iocommand.buf = (unsigned char *)buff;
|
||||
|
||||
if ((err = ioctl(fd, CCISS_PASSTHRU, &iocommand)))
|
||||
{
|
||||
pout("CCISS ioctl error %d (fd %d CDBLen %u buf_size %u)\n",
|
||||
fd, err, CDBlen, size);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int cciss_getlun(int device, int target, unsigned char *physlun, int report)
|
||||
{
|
||||
unsigned char CDB[16] = {0};
|
||||
ReportLunData_struct *luns;
|
||||
int reportlunsize = sizeof(*luns) + CISS_MAX_PHYS_LUN * 8;
|
||||
int ret;
|
||||
|
||||
luns = (ReportLunData_struct *)malloc(reportlunsize);
|
||||
|
||||
memset(luns, 0, reportlunsize);
|
||||
|
||||
/* Get Physical LUN Info (for physical device) */
|
||||
CDB[0] = CISS_REPORT_PHYS;
|
||||
CDB[6] = (reportlunsize >> 24) & 0xFF; /* MSB */
|
||||
CDB[7] = (reportlunsize >> 16) & 0xFF;
|
||||
CDB[8] = (reportlunsize >> 8) & 0xFF;
|
||||
CDB[9] = reportlunsize & 0xFF;
|
||||
|
||||
if ((ret = cciss_sendpassthru(0, CDB, 12, (char *)luns, reportlunsize, 0, NULL, device)))
|
||||
{
|
||||
free(luns);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (report > 1)
|
||||
{
|
||||
unsigned int i, j;
|
||||
unsigned char *stuff = (unsigned char *)luns;
|
||||
|
||||
pout("\n===== [%s] DATA START (BASE-16) =====\n", "LUN DATA");
|
||||
for (i = 0; i < (sizeof(_ReportLUNdata_struct) + 15) / 16; i++)
|
||||
{
|
||||
pout("%03d-%03d: ", 16 * i, 16 * (i + 1) - 1);
|
||||
for (j = 0; j < 15; j++)
|
||||
pout("%02x ", *stuff++);
|
||||
pout("%02x\n", *stuff++);
|
||||
}
|
||||
pout("===== [%s] DATA END (%u Bytes) =====\n\n", "LUN DATA", (unsigned)sizeof(_ReportLUNdata_struct));
|
||||
}
|
||||
|
||||
if (target >= 0 && target < (int)be32toh(luns->LUNListLength) / 8)
|
||||
{
|
||||
memcpy(physlun, luns->LUN[target], 8);
|
||||
free(luns);
|
||||
return 0;
|
||||
}
|
||||
|
||||
free(luns);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* cciss.h
|
||||
*
|
||||
* Home page of code is: http://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2007 Sergey Svishchev
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef CCISS_H_
|
||||
#define CCISS_H_
|
||||
|
||||
#define CCISS_H_CVSID "$Id: cciss.h 4761 2018-08-20 19:33:04Z chrfranke $"
|
||||
|
||||
int cciss_io_interface(int device, int target,
|
||||
struct scsi_cmnd_io *iop, int report);
|
||||
|
||||
#endif /* CCISS_H_ */
|
|
@ -1,188 +0,0 @@
|
|||
/* config.h. Generated from config.h.in by configure. */
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define if building universal (internal helper macro) */
|
||||
/* #undef AC_APPLE_UNIVERSAL_BUILD */
|
||||
|
||||
/* freebsd ciss header location */
|
||||
/* #undef CISS_LOCATION */
|
||||
|
||||
/* smartmontools CVS Tag */
|
||||
#define CONFIG_H_CVSID "$Id: configure.ac 5338 2022-02-28 16:34:26Z chrfranke $"
|
||||
|
||||
/* Define to 1 if C++ compiler supports __attribute__((packed)) */
|
||||
#define HAVE_ATTR_PACKED 1
|
||||
|
||||
/* Define to 1 if you have the <byteswap.h> header file. */
|
||||
#define HAVE_BYTESWAP_H 1
|
||||
|
||||
/* Define to 1 if you have the <cap-ng.h> header file. */
|
||||
/* #undef HAVE_CAP_NG_H */
|
||||
|
||||
/* Define to 1 if you have the <dev/ata/atavar.h> header file. */
|
||||
/* #undef HAVE_DEV_ATA_ATAVAR_H */
|
||||
|
||||
/* Define to 1 if you have the <dev/ciss/cissio.h> header file. */
|
||||
/* #undef HAVE_DEV_CISS_CISSIO_H */
|
||||
|
||||
/* Define to 1 if you have the `getopt_long' function. */
|
||||
#define HAVE_GETOPT_LONG 1
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the `cap-ng' library (-lcap-ng). */
|
||||
/* #undef HAVE_LIBCAP_NG */
|
||||
|
||||
/* Define to 1 if you have the `selinux' library (-lselinux). */
|
||||
/* #undef HAVE_LIBSELINUX */
|
||||
|
||||
/* Define to 1 if you have the `systemd' library (-lsystemd). */
|
||||
#define HAVE_LIBSYSTEMD 1
|
||||
|
||||
/* Define to 1 if you have the `usb' library (-lusb). */
|
||||
/* #undef HAVE_LIBUSB */
|
||||
|
||||
/* Define to 1 if you have the <linux/cciss_ioctl.h> header file. */
|
||||
#define HAVE_LINUX_CCISS_IOCTL_H 1
|
||||
|
||||
/* Define to 1 if you have the <linux/compiler.h> header file. */
|
||||
/* #undef HAVE_LINUX_COMPILER_H */
|
||||
|
||||
/* Define to 1 if you have the <locale.h> header file. */
|
||||
#define HAVE_LOCALE_H 1
|
||||
|
||||
/* Define to 1 if the type `long double' works and has more range or precision
|
||||
than `double'. */
|
||||
#define HAVE_LONG_DOUBLE_WIDER 1
|
||||
|
||||
/* Define to 1 if the OS provides a POSIX API */
|
||||
#define HAVE_POSIX_API 1
|
||||
|
||||
/* Define to 1 if you have the `regcomp' function. */
|
||||
#define HAVE_REGCOMP 1
|
||||
|
||||
/* Define to 1 if you have the <selinux/selinux.h> header file. */
|
||||
/* #undef HAVE_SELINUX_SELINUX_H */
|
||||
|
||||
/* Define to 1 if you have the `sigaction' function. */
|
||||
#define HAVE_SIGACTION 1
|
||||
|
||||
/* Define to 1 if you have the `sigset' function. */
|
||||
/* #undef HAVE_SIGSET */
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdio.h> header file. */
|
||||
/* #undef HAVE_STDIO_H */
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the <systemd/sd-daemon.h> header file. */
|
||||
#define HAVE_SYSTEMD_SD_DAEMON_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/sysmacros.h> header file. */
|
||||
#define HAVE_SYS_SYSMACROS_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/tweio.h> header file. */
|
||||
/* #undef HAVE_SYS_TWEIO_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/twereg.h> header file. */
|
||||
/* #undef HAVE_SYS_TWEREG_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/tw_osl_ioctl.h> header file. */
|
||||
/* #undef HAVE_SYS_TW_OSL_IOCTL_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to 1 if the system has the type `__int128'. */
|
||||
#define HAVE___INT128 1
|
||||
|
||||
/* Define to 1 to use generic LE/BE code instead */
|
||||
/* #undef IGNORE_FAST_LEBE */
|
||||
|
||||
/* Define to 1 if os_*.cpp still uses the old interface */
|
||||
/* #undef OLD_INTERFACE */
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "smartmontools"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT "smartmontools-support@listi.jpberlin.de"
|
||||
|
||||
/* smartmontools Home Page */
|
||||
#define PACKAGE_HOMEPAGE "https://www.smartmontools.org/"
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "smartmontools"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "smartmontools 7.3"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "smartmontools"
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "7.3"
|
||||
|
||||
/* Define to 1 to enable check on each SCSI cdb */
|
||||
/* #undef SCSI_CDB_CHECK */
|
||||
|
||||
/* smartmontools Build Host */
|
||||
#define SMARTMONTOOLS_BUILD_HOST "x86_64-pc-linux-gnu"
|
||||
|
||||
/* smartmontools Configure Arguments */
|
||||
#define SMARTMONTOOLS_CONFIGURE_ARGS ""
|
||||
|
||||
/* smartmontools Release Date */
|
||||
#define SMARTMONTOOLS_RELEASE_DATE "2022-02-28"
|
||||
|
||||
/* smartmontools Release Time */
|
||||
#define SMARTMONTOOLS_RELEASE_TIME "16:33:40 UTC"
|
||||
|
||||
/* Define to 1 if all of the C90 standard headers exist (not just the ones
|
||||
required in a freestanding environment). This macro is provided for
|
||||
backward compatibility; new code need not use it. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "7.3"
|
||||
|
||||
/* Define to 1 to use C++11 std::regex instead of POSIX regex(3) */
|
||||
/* #undef WITH_CXX11_REGEX */
|
||||
|
||||
/* Define to 1 to include NVMe devices in smartd DEVICESCAN. */
|
||||
#define WITH_NVME_DEVICESCAN 1
|
||||
|
||||
/* Define to 1 to enable legacy ATA support on Solaris SPARC. */
|
||||
/* #undef WITH_SOLARIS_SPARC_ATA */
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
||||
#if defined __BIG_ENDIAN__
|
||||
#define WORDS_BIGENDIAN 1
|
||||
#endif
|
||||
#else
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
/* # undef WORDS_BIGENDIAN */
|
||||
#endif
|
||||
#endif
|
|
@ -1,689 +0,0 @@
|
|||
/*
|
||||
* dev_areca.cpp
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2012 Hank Wu <hank@areca.com.tw>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "dev_interface.h"
|
||||
#include "dev_areca.h"
|
||||
|
||||
const char *dev_areca_cpp_cvsid = "$Id: dev_areca.cpp 5337 2022-02-27 07:53:55Z dpgilbert $" DEV_ARECA_H_CVSID;
|
||||
|
||||
#include "atacmds.h"
|
||||
#include "scsicmds.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#if 0 // For debugging areca code
|
||||
static void dumpdata(unsigned char *block, int len)
|
||||
{
|
||||
int ln = (len / 16) + 1; // total line#
|
||||
unsigned char c;
|
||||
int pos = 0;
|
||||
|
||||
printf(" Address = %p, Length = (0x%x)%d\n", block, len, len);
|
||||
printf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F ASCII \n");
|
||||
printf("=====================================================================\n");
|
||||
|
||||
for ( int l = 0; l < ln && len; l++ )
|
||||
{
|
||||
// printf the line# and the HEX data
|
||||
// if a line data length < 16 then append the space to the tail of line to reach 16 chars
|
||||
printf("%02X | ", l);
|
||||
for ( pos = 0; pos < 16 && len; pos++, len-- )
|
||||
{
|
||||
c = block[l*16+pos];
|
||||
printf("%02X ", c);
|
||||
}
|
||||
|
||||
if ( pos < 16 )
|
||||
{
|
||||
for ( int loop = pos; loop < 16; loop++ )
|
||||
{
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
|
||||
// print ASCII char
|
||||
for ( int loop = 0; loop < pos; loop++ )
|
||||
{
|
||||
c = block[l*16+loop];
|
||||
if ( c >= 0x20 && c <= 0x7F )
|
||||
{
|
||||
printf("%c", c);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(".");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("=====================================================================\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
generic_areca_device::generic_areca_device(smart_interface *intf, const char *dev_name, int disknum, int encnum)
|
||||
: smart_device(intf, dev_name, "areca", "areca"),
|
||||
m_disknum(disknum),
|
||||
m_encnum(encnum)
|
||||
{
|
||||
set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
|
||||
}
|
||||
|
||||
generic_areca_device::~generic_areca_device()
|
||||
{
|
||||
}
|
||||
|
||||
// PURPOSE
|
||||
// This is an interface routine meant to isolate the OS dependent
|
||||
// parts of the code, and to provide a debugging interface. Each
|
||||
// different port and OS needs to provide it's own interface. This
|
||||
// is the Windows interface to the Areca "arcmsr" driver. It allows ATA
|
||||
// commands to be passed through the SCSI driver.
|
||||
// DETAILED DESCRIPTION OF ARGUMENTS
|
||||
// fd: is the file descriptor provided by open()
|
||||
// disknum is the disk number (0 to 127) in the RAID array
|
||||
// command: defines the different operations.
|
||||
// select: additional input data if needed (which log, which type of
|
||||
// self-test).
|
||||
// data: location to write output data, if needed (512 bytes).
|
||||
// Note: not all commands use all arguments.
|
||||
// RETURN VALUES
|
||||
// -1 if the command failed
|
||||
// 0 if the command succeeded,
|
||||
// STATUS_CHECK routine:
|
||||
// -1 if the command failed
|
||||
// 0 if the command succeeded and disk SMART status is "OK"
|
||||
// 1 if the command succeeded and disk SMART status is "FAILING"
|
||||
int generic_areca_device::arcmsr_command_handler(unsigned long arcmsr_cmd, unsigned char *data, int data_len)
|
||||
{
|
||||
if (arcmsr_cmd >= ARCMSR_CMD_TOTAL)
|
||||
return -1;
|
||||
|
||||
static const unsigned int cmds[ARCMSR_CMD_TOTAL] =
|
||||
{
|
||||
ARCMSR_IOCTL_READ_RQBUFFER,
|
||||
ARCMSR_IOCTL_WRITE_WQBUFFER,
|
||||
ARCMSR_IOCTL_CLEAR_RQBUFFER,
|
||||
ARCMSR_IOCTL_CLEAR_WQBUFFER,
|
||||
ARCMSR_IOCTL_RETURN_CODE_3F};
|
||||
|
||||
int ioctlreturn = 0;
|
||||
sSRB_BUFFER sBuf;
|
||||
struct scsi_cmnd_io iop = {};
|
||||
int dir = DXFER_TO_DEVICE;
|
||||
|
||||
uint8_t cdb[10] = {};
|
||||
uint8_t sense[32] = {};
|
||||
|
||||
unsigned char *areca_return_packet;
|
||||
int total = 0;
|
||||
int expected = -1;
|
||||
unsigned char return_buff[2048] = {0};
|
||||
unsigned char *ptr = &return_buff[0];
|
||||
|
||||
memset((unsigned char *)&sBuf, 0, sizeof(sBuf));
|
||||
|
||||
sBuf.srbioctl.HeaderLength = sizeof(sARCMSR_IO_HDR);
|
||||
memcpy(sBuf.srbioctl.Signature, ARECA_SIG_STR, strlen(ARECA_SIG_STR));
|
||||
sBuf.srbioctl.Timeout = 10000;
|
||||
sBuf.srbioctl.ControlCode = cmds[arcmsr_cmd];
|
||||
|
||||
switch (arcmsr_cmd)
|
||||
{
|
||||
// command for writing data to driver
|
||||
case ARCMSR_WRITE_WQBUFFER:
|
||||
if (data && data_len)
|
||||
{
|
||||
sBuf.srbioctl.Length = data_len;
|
||||
memcpy((unsigned char *)sBuf.ioctldatabuffer, (unsigned char *)data, data_len);
|
||||
}
|
||||
/* FALLTHRU */
|
||||
// commands for clearing related buffer of driver
|
||||
case ARCMSR_CLEAR_RQBUFFER:
|
||||
case ARCMSR_CLEAR_WQBUFFER:
|
||||
cdb[0] = 0x3B; // SCSI_WRITE_BUF command;
|
||||
break;
|
||||
// command for reading data from driver
|
||||
case ARCMSR_READ_RQBUFFER:
|
||||
// command for identifying driver
|
||||
case ARCMSR_RETURN_CODE_3F:
|
||||
cdb[0] = 0x3C; // SCSI_READ_BUF command;
|
||||
dir = DXFER_FROM_DEVICE;
|
||||
break;
|
||||
default:
|
||||
// unknown arcmsr commands
|
||||
return -1;
|
||||
}
|
||||
|
||||
cdb[1] = 0x01;
|
||||
cdb[2] = 0xf0;
|
||||
cdb[5] = cmds[arcmsr_cmd] >> 24;
|
||||
cdb[6] = cmds[arcmsr_cmd] >> 16;
|
||||
cdb[7] = cmds[arcmsr_cmd] >> 8;
|
||||
cdb[8] = cmds[arcmsr_cmd] & 0x0F;
|
||||
|
||||
iop.dxfer_dir = dir;
|
||||
iop.dxfer_len = sizeof(sBuf);
|
||||
iop.dxferp = (unsigned char *)&sBuf;
|
||||
iop.cmnd = cdb;
|
||||
iop.cmnd_len = sizeof(cdb);
|
||||
iop.sensep = sense;
|
||||
iop.max_sense_len = sizeof(sense);
|
||||
iop.timeout = SCSI_TIMEOUT_DEFAULT;
|
||||
|
||||
while (1)
|
||||
{
|
||||
ioctlreturn = arcmsr_do_scsi_io(&iop);
|
||||
if (ioctlreturn || iop.scsi_status)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (arcmsr_cmd != ARCMSR_READ_RQBUFFER)
|
||||
{
|
||||
// if succeeded, just returns the length of outgoing data
|
||||
return data_len;
|
||||
}
|
||||
|
||||
if (sBuf.srbioctl.Length)
|
||||
{
|
||||
memcpy(ptr, &sBuf.ioctldatabuffer[0], sBuf.srbioctl.Length);
|
||||
ptr += sBuf.srbioctl.Length;
|
||||
total += sBuf.srbioctl.Length;
|
||||
// the returned bytes enough to compute payload length ?
|
||||
if (expected < 0 && total >= 5)
|
||||
{
|
||||
areca_return_packet = (unsigned char *)&return_buff[0];
|
||||
if (areca_return_packet[0] == 0x5E &&
|
||||
areca_return_packet[1] == 0x01 &&
|
||||
areca_return_packet[2] == 0x61)
|
||||
{
|
||||
// valid header, let's compute the returned payload length,
|
||||
// we expected the total length is
|
||||
// payload + 3 bytes header + 2 bytes length + 1 byte checksum
|
||||
expected = areca_return_packet[4] * 256 + areca_return_packet[3] + 6;
|
||||
}
|
||||
}
|
||||
|
||||
if (total >= 7 && total >= expected)
|
||||
{
|
||||
// printf("total bytes received = %d, expected length = %d\n", total, expected);
|
||||
|
||||
// ------ Okay! we received enough --------
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Deal with the different error cases
|
||||
if (arcmsr_cmd == ARCMSR_RETURN_CODE_3F)
|
||||
{
|
||||
// Silence the ARCMSR_IOCTL_RETURN_CODE_3F's error, no pout(...)
|
||||
return -4;
|
||||
}
|
||||
|
||||
if (ioctlreturn)
|
||||
{
|
||||
pout("do_scsi_cmnd_io with write buffer failed code = %x\n", ioctlreturn);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (iop.scsi_status)
|
||||
{
|
||||
pout("io_hdr.scsi_status with write buffer failed code = %x\n", iop.scsi_status);
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (data)
|
||||
{
|
||||
memcpy(data, return_buff, total);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
bool generic_areca_device::arcmsr_probe()
|
||||
{
|
||||
if (!is_open())
|
||||
{
|
||||
open();
|
||||
}
|
||||
|
||||
if (arcmsr_command_handler(ARCMSR_RETURN_CODE_3F, NULL, 0) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int generic_areca_device::arcmsr_ui_handler(unsigned char *areca_packet, int areca_packet_len, unsigned char *result)
|
||||
{
|
||||
int expected = 0;
|
||||
unsigned char return_buff[2048];
|
||||
unsigned char cs = 0;
|
||||
int cs_pos = 0;
|
||||
|
||||
// ----- ADD CHECKSUM -----
|
||||
cs_pos = areca_packet_len - 1;
|
||||
for (int i = 3; i < cs_pos; i++)
|
||||
{
|
||||
areca_packet[cs_pos] += areca_packet[i];
|
||||
}
|
||||
|
||||
if (!arcmsr_lock())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
expected = arcmsr_command_handler(ARCMSR_CLEAR_RQBUFFER, NULL, 0);
|
||||
if (expected == -3)
|
||||
{
|
||||
return set_err(EIO);
|
||||
}
|
||||
arcmsr_command_handler(ARCMSR_CLEAR_WQBUFFER, NULL, 0);
|
||||
expected = arcmsr_command_handler(ARCMSR_WRITE_WQBUFFER, areca_packet, areca_packet_len);
|
||||
if (expected > 0)
|
||||
{
|
||||
expected = arcmsr_command_handler(ARCMSR_READ_RQBUFFER, return_buff, sizeof(return_buff));
|
||||
}
|
||||
|
||||
if (expected < 3 + 1) // Prefix + Checksum
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!arcmsr_unlock())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ----- VERIFY THE CHECKSUM -----
|
||||
cs = 0;
|
||||
for (int loop = 3; loop < expected - 1; loop++)
|
||||
{
|
||||
cs += return_buff[loop];
|
||||
}
|
||||
|
||||
if (return_buff[expected - 1] != cs)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(result, return_buff, expected);
|
||||
|
||||
return expected;
|
||||
}
|
||||
|
||||
int generic_areca_device::arcmsr_get_controller_type()
|
||||
{
|
||||
int expected = 0;
|
||||
unsigned char return_buff[2048];
|
||||
unsigned char areca_packet[] = {0x5E, 0x01, 0x61, 0x01, 0x00, 0x23, 0x00};
|
||||
|
||||
memset(return_buff, 0, sizeof(return_buff));
|
||||
expected = arcmsr_ui_handler(areca_packet, sizeof(areca_packet), return_buff);
|
||||
if (expected < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return return_buff[0xc2];
|
||||
}
|
||||
|
||||
int generic_areca_device::arcmsr_get_dev_type()
|
||||
{
|
||||
int expected = 0;
|
||||
unsigned char return_buff[2048];
|
||||
int ctlr_type = -1;
|
||||
int encnum = get_encnum();
|
||||
int disknum = get_disknum();
|
||||
unsigned char areca_packet[] = {0x5E, 0x01, 0x61, 0x03, 0x00, 0x22,
|
||||
(unsigned char)(disknum - 1), (unsigned char)(encnum - 1), 0x00};
|
||||
|
||||
memset(return_buff, 0, sizeof(return_buff));
|
||||
expected = arcmsr_ui_handler(areca_packet, sizeof(areca_packet), return_buff);
|
||||
if (expected < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctlr_type = arcmsr_get_controller_type();
|
||||
|
||||
if (ctlr_type < 0)
|
||||
{
|
||||
return ctlr_type;
|
||||
}
|
||||
|
||||
if (ctlr_type == 0x02 /* SATA Controllers */ ||
|
||||
(ctlr_type == 0x03 /* SAS Controllers */ && return_buff[0x52] & 0x01 /* SATA devices behind SAS Controller */))
|
||||
{
|
||||
// SATA device
|
||||
return 1;
|
||||
}
|
||||
|
||||
// SAS device
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool generic_areca_device::arcmsr_ata_pass_through(const ata_cmd_in &in, ata_cmd_out &out)
|
||||
{
|
||||
// ATA input registers
|
||||
typedef struct _ATA_INPUT_REGISTERS
|
||||
{
|
||||
unsigned char features;
|
||||
unsigned char sector_count;
|
||||
unsigned char sector_number;
|
||||
unsigned char cylinder_low;
|
||||
unsigned char cylinder_high;
|
||||
unsigned char device_head;
|
||||
unsigned char command;
|
||||
unsigned char reserved[8];
|
||||
unsigned char data[512]; // [in/out] buffer for outgoing/incoming data
|
||||
} sATA_INPUT_REGISTERS;
|
||||
|
||||
// ATA output registers
|
||||
// Note: The output registers is re-sorted for areca internal use only
|
||||
typedef struct _ATA_OUTPUT_REGISTERS
|
||||
{
|
||||
unsigned char error;
|
||||
unsigned char status;
|
||||
unsigned char sector_count;
|
||||
unsigned char sector_number;
|
||||
unsigned char cylinder_low;
|
||||
unsigned char cylinder_high;
|
||||
} sATA_OUTPUT_REGISTERS;
|
||||
|
||||
// Areca packet format for outgoing:
|
||||
// B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61
|
||||
// B[3~4] : 2 bytes command length + variant data length, little endian
|
||||
// B[5] : 1 bytes areca defined command code, ATA passthrough command code is 0x1c
|
||||
// B[6~last-1] : variant bytes payload data
|
||||
// B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1])
|
||||
//
|
||||
//
|
||||
// header 3 bytes length 2 bytes cmd 1 byte payload data x bytes cs 1 byte
|
||||
// +--------------------------------------------------------------------------------+
|
||||
// + 0x5E 0x01 0x61 | 0x00 0x00 | 0x1c | .................... | 0x00 |
|
||||
// +--------------------------------------------------------------------------------+
|
||||
//
|
||||
|
||||
// Areca packet format for incoming:
|
||||
// B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61
|
||||
// B[3~4] : 2 bytes payload length, little endian
|
||||
// B[5~last-1] : variant bytes returned payload data
|
||||
// B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1])
|
||||
//
|
||||
//
|
||||
// header 3 bytes length 2 bytes payload data x bytes cs 1 byte
|
||||
// +-------------------------------------------------------------------+
|
||||
// + 0x5E 0x01 0x61 | 0x00 0x00 | .................... | 0x00 |
|
||||
// +-------------------------------------------------------------------+
|
||||
unsigned char areca_packet[640];
|
||||
int areca_packet_len = sizeof(areca_packet);
|
||||
unsigned char return_buff[2048];
|
||||
int expected = 0;
|
||||
|
||||
sATA_INPUT_REGISTERS *ata_cmd;
|
||||
|
||||
// For debugging
|
||||
#if 0
|
||||
memset(sInq, 0, sizeof(sInq));
|
||||
scsiStdInquiry(fd, (unsigned char *)sInq, (int)sizeof(sInq));
|
||||
dumpdata((unsigned char *)sInq, sizeof(sInq));
|
||||
#endif
|
||||
memset(areca_packet, 0, areca_packet_len);
|
||||
|
||||
// ----- BEGIN TO SETUP HEADERS -------
|
||||
areca_packet[0] = 0x5E;
|
||||
areca_packet[1] = 0x01;
|
||||
areca_packet[2] = 0x61;
|
||||
areca_packet[3] = (unsigned char)((areca_packet_len - 6) & 0xff);
|
||||
areca_packet[4] = (unsigned char)(((areca_packet_len - 6) >> 8) & 0xff);
|
||||
areca_packet[5] = 0x1c; // areca defined code for ATA passthrough command
|
||||
|
||||
// ----- BEGIN TO SETUP PAYLOAD DATA -----
|
||||
memcpy(&areca_packet[7], "SmrT", 4); // areca defined password
|
||||
ata_cmd = (sATA_INPUT_REGISTERS *)&areca_packet[12];
|
||||
|
||||
// Set registers
|
||||
{
|
||||
const ata_in_regs &r = in.in_regs;
|
||||
ata_cmd->features = r.features;
|
||||
ata_cmd->sector_count = r.sector_count;
|
||||
ata_cmd->sector_number = r.lba_low;
|
||||
ata_cmd->cylinder_low = r.lba_mid;
|
||||
ata_cmd->cylinder_high = r.lba_high;
|
||||
ata_cmd->device_head = r.device;
|
||||
ata_cmd->command = r.command;
|
||||
}
|
||||
bool readdata = false;
|
||||
if (in.direction == ata_cmd_in::data_in)
|
||||
{
|
||||
readdata = true;
|
||||
// the command will read data
|
||||
areca_packet[6] = 0x13;
|
||||
}
|
||||
else if (in.direction == ata_cmd_in::no_data)
|
||||
{
|
||||
// the commands will return no data
|
||||
areca_packet[6] = 0x15;
|
||||
}
|
||||
else if (in.direction == ata_cmd_in::data_out)
|
||||
{
|
||||
// the commands will write data
|
||||
memcpy(ata_cmd->data, in.buffer, in.size);
|
||||
areca_packet[6] = 0x14;
|
||||
}
|
||||
else
|
||||
{
|
||||
// COMMAND NOT SUPPORTED VIA ARECA IOCTL INTERFACE
|
||||
return set_err(ENOSYS);
|
||||
}
|
||||
|
||||
areca_packet[11] = get_disknum() - 1; // disk#
|
||||
areca_packet[19] = get_encnum() - 1; // enc#
|
||||
|
||||
// ----- BEGIN TO SEND TO ARECA DRIVER ------
|
||||
expected = arcmsr_ui_handler(areca_packet, areca_packet_len, return_buff);
|
||||
if (expected < 0)
|
||||
{
|
||||
return set_err(EIO);
|
||||
}
|
||||
|
||||
sATA_OUTPUT_REGISTERS *ata_out = (sATA_OUTPUT_REGISTERS *)&return_buff[5];
|
||||
if (ata_out->status)
|
||||
{
|
||||
if (in.in_regs.command == ATA_IDENTIFY_DEVICE && !nonempty((unsigned char *)in.buffer, in.size))
|
||||
{
|
||||
return set_err(ENODEV, "No drive on port %d", get_disknum());
|
||||
}
|
||||
}
|
||||
|
||||
// returns with data
|
||||
if (readdata)
|
||||
{
|
||||
memcpy(in.buffer, &return_buff[7], in.size);
|
||||
}
|
||||
|
||||
// Return register values
|
||||
{
|
||||
ata_out_regs &r = out.out_regs;
|
||||
r.error = ata_out->error;
|
||||
r.sector_count = ata_out->sector_count;
|
||||
r.lba_low = ata_out->sector_number;
|
||||
r.lba_mid = ata_out->cylinder_low;
|
||||
r.lba_high = ata_out->cylinder_high;
|
||||
r.status = ata_out->status;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool generic_areca_device::arcmsr_scsi_pass_through(struct scsi_cmnd_io *iop)
|
||||
{
|
||||
// Areca packet format for outgoing:
|
||||
// B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61
|
||||
// B[3~4] : 2 bytes command length + variant data length, little endian
|
||||
// B[5] : 1 bytes areca defined command code
|
||||
// B[6~last-1] : variant bytes payload data
|
||||
// B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1])
|
||||
//
|
||||
//
|
||||
// header 3 bytes length 2 bytes cmd 1 byte payload data x bytes cs 1 byte
|
||||
// +--------------------------------------------------------------------------------+
|
||||
// + 0x5E 0x01 0x61 | 0x00 0x00 | 0x1c | .................... | 0x00 |
|
||||
// +--------------------------------------------------------------------------------+
|
||||
//
|
||||
|
||||
// Areca packet format for incoming:
|
||||
// B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61
|
||||
// B[3~4] : 2 bytes payload length, little endian
|
||||
// B[5~last-1] : variant bytes returned payload data
|
||||
// B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1])
|
||||
//
|
||||
//
|
||||
// header 3 bytes length 2 bytes payload data x bytes cs 1 byte
|
||||
// +-------------------------------------------------------------------+
|
||||
// + 0x5E 0x01 0x61 | 0x00 0x00 | .................... | 0x00 |
|
||||
// +-------------------------------------------------------------------+
|
||||
unsigned char areca_packet[640];
|
||||
int areca_packet_len = sizeof(areca_packet);
|
||||
unsigned char return_buff[2048];
|
||||
int expected = 0;
|
||||
|
||||
if (iop->cmnd_len > 16)
|
||||
{
|
||||
set_err(EINVAL, "cmnd_len too large");
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(areca_packet, 0, areca_packet_len);
|
||||
|
||||
// ----- BEGIN TO SETUP HEADERS -------
|
||||
areca_packet[0] = 0x5E;
|
||||
areca_packet[1] = 0x01;
|
||||
areca_packet[2] = 0x61;
|
||||
areca_packet[3] = (unsigned char)((areca_packet_len - 6) & 0xff);
|
||||
areca_packet[4] = (unsigned char)(((areca_packet_len - 6) >> 8) & 0xff);
|
||||
areca_packet[5] = 0x1c;
|
||||
|
||||
// ----- BEGIN TO SETUP PAYLOAD DATA -----
|
||||
areca_packet[6] = 0x16; // scsi pass through
|
||||
memcpy(&areca_packet[7], "SmrT", 4); // areca defined password
|
||||
areca_packet[12] = iop->cmnd_len; // cdb length
|
||||
memcpy(&areca_packet[35], iop->cmnd, iop->cmnd_len); // cdb
|
||||
areca_packet[15] = (unsigned char)iop->dxfer_len; // 15(LSB) ~ 18(MSB): data length ( max=512 bytes)
|
||||
areca_packet[16] = (unsigned char)(iop->dxfer_len >> 8);
|
||||
areca_packet[17] = (unsigned char)(iop->dxfer_len >> 16);
|
||||
areca_packet[18] = (unsigned char)(iop->dxfer_len >> 24);
|
||||
if (iop->dxfer_dir == DXFER_TO_DEVICE)
|
||||
{
|
||||
areca_packet[13] |= 0x01;
|
||||
memcpy(&areca_packet[67], iop->dxferp, iop->dxfer_len);
|
||||
}
|
||||
else if (iop->dxfer_dir == DXFER_FROM_DEVICE)
|
||||
{
|
||||
}
|
||||
else if (iop->dxfer_dir == DXFER_NONE)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
// COMMAND NOT SUPPORTED VIA ARECA IOCTL INTERFACE
|
||||
return set_err(ENOSYS);
|
||||
}
|
||||
|
||||
areca_packet[11] = get_disknum() - 1; // disk#
|
||||
areca_packet[19] = get_encnum() - 1; // enc#
|
||||
|
||||
// ----- BEGIN TO SEND TO ARECA DRIVER ------
|
||||
expected = arcmsr_ui_handler(areca_packet, areca_packet_len, return_buff);
|
||||
|
||||
if (expected < 0)
|
||||
return set_err(EIO, "arcmsr_scsi_pass_through: I/O error");
|
||||
if (expected < 15) // 7 bytes if port is empty
|
||||
return set_err(EIO, "arcmsr_scsi_pass_through: missing data (%d bytes, expected %d)", expected, 15);
|
||||
|
||||
int scsi_status = return_buff[5];
|
||||
int in_data_len = return_buff[11] | return_buff[12] << 8 | return_buff[13] << 16 | return_buff[14] << 24;
|
||||
|
||||
if (iop->dxfer_dir == DXFER_FROM_DEVICE)
|
||||
{
|
||||
memset(iop->dxferp, 0, iop->dxfer_len); // need?
|
||||
memcpy(iop->dxferp, &return_buff[15], in_data_len);
|
||||
}
|
||||
|
||||
if (scsi_status == 0xE1 /* Underrun, actual data length < requested data length */)
|
||||
{
|
||||
// don't care, just ignore
|
||||
scsi_status = 0x0;
|
||||
}
|
||||
|
||||
if (scsi_status != 0x00 && scsi_status != SCSI_STATUS_CHECK_CONDITION)
|
||||
{
|
||||
return set_err(EIO);
|
||||
}
|
||||
|
||||
if (scsi_status == SCSI_STATUS_CHECK_CONDITION)
|
||||
{
|
||||
// check condition
|
||||
iop->scsi_status = SCSI_STATUS_CHECK_CONDITION;
|
||||
iop->resp_sense_len = 4;
|
||||
iop->sensep[0] = return_buff[7];
|
||||
iop->sensep[1] = return_buff[8];
|
||||
iop->sensep[2] = return_buff[9];
|
||||
iop->sensep[3] = return_buff[10];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
areca_ata_device::areca_ata_device(smart_interface *intf, const char *dev_name, int disknum, int encnum)
|
||||
: smart_device(intf, dev_name, "areca", "areca")
|
||||
{
|
||||
set_encnum(encnum);
|
||||
set_disknum(disknum);
|
||||
set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
|
||||
}
|
||||
|
||||
areca_ata_device::~areca_ata_device()
|
||||
{
|
||||
}
|
||||
|
||||
bool areca_ata_device::ata_pass_through(const ata_cmd_in &in, ata_cmd_out &out)
|
||||
{
|
||||
if (!ata_cmd_is_supported(in,
|
||||
ata_device::supports_data_out |
|
||||
ata_device::supports_output_regs |
|
||||
// ata_device::supports_multi_sector | // TODO
|
||||
ata_device::supports_48bit_hi_null,
|
||||
"Areca"))
|
||||
return false;
|
||||
|
||||
return arcmsr_ata_pass_through(in, out);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
areca_scsi_device::areca_scsi_device(smart_interface *intf, const char *dev_name, int disknum, int encnum)
|
||||
: smart_device(intf, dev_name, "areca", "areca")
|
||||
{
|
||||
set_encnum(encnum);
|
||||
set_disknum(disknum);
|
||||
set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
|
||||
}
|
||||
|
||||
areca_scsi_device::~areca_scsi_device()
|
||||
{
|
||||
}
|
||||
|
||||
bool areca_scsi_device::scsi_pass_through(struct scsi_cmnd_io *iop)
|
||||
{
|
||||
return arcmsr_scsi_pass_through(iop);
|
||||
}
|
|
@ -1,187 +0,0 @@
|
|||
/*
|
||||
* dev_areca.h
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2012 Hank Wu <hank@areca.com.tw>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef DEV_ARECA_H
|
||||
#define DEV_ARECA_H
|
||||
|
||||
#define DEV_ARECA_H_CVSID "$Id: dev_areca.h 5198 2021-02-01 20:36:02Z chrfranke $"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/// Areca RAID support
|
||||
|
||||
/* GENERIC ARECA IO CONTROL CODE*/
|
||||
enum _GENERIC_ARCMSR_CMDS
|
||||
{
|
||||
ARCMSR_READ_RQBUFFER = 0,
|
||||
ARCMSR_WRITE_WQBUFFER,
|
||||
ARCMSR_CLEAR_RQBUFFER,
|
||||
ARCMSR_CLEAR_WQBUFFER,
|
||||
ARCMSR_RETURN_CODE_3F,
|
||||
ARCMSR_CMD_TOTAL
|
||||
};
|
||||
|
||||
#define ARECA_SIG_STR "ARCMSR"
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#define ARCMSR_IOCTL_READ_RQBUFFER 0x90002004
|
||||
#define ARCMSR_IOCTL_WRITE_WQBUFFER 0x90002008
|
||||
#define ARCMSR_IOCTL_CLEAR_RQBUFFER 0x9000200C
|
||||
#define ARCMSR_IOCTL_CLEAR_WQBUFFER 0x90002010
|
||||
#define ARCMSR_IOCTL_RETURN_CODE_3F 0x90002018
|
||||
#elif defined(__linux__)
|
||||
/*DeviceType*/
|
||||
#define ARECA_SATA_RAID 0x90000000
|
||||
/*FunctionCode*/
|
||||
#define FUNCTION_READ_RQBUFFER 0x0801
|
||||
#define FUNCTION_WRITE_WQBUFFER 0x0802
|
||||
#define FUNCTION_CLEAR_RQBUFFER 0x0803
|
||||
#define FUNCTION_CLEAR_WQBUFFER 0x0804
|
||||
#define FUNCTION_RETURN_CODE_3F 0x0806
|
||||
|
||||
/* ARECA IO CONTROL CODE*/
|
||||
#define ARCMSR_IOCTL_READ_RQBUFFER (ARECA_SATA_RAID | FUNCTION_READ_RQBUFFER)
|
||||
#define ARCMSR_IOCTL_WRITE_WQBUFFER (ARECA_SATA_RAID | FUNCTION_WRITE_WQBUFFER)
|
||||
#define ARCMSR_IOCTL_CLEAR_RQBUFFER (ARECA_SATA_RAID | FUNCTION_CLEAR_RQBUFFER)
|
||||
#define ARCMSR_IOCTL_CLEAR_WQBUFFER (ARECA_SATA_RAID | FUNCTION_CLEAR_WQBUFFER)
|
||||
#define ARCMSR_IOCTL_RETURN_CODE_3F (ARECA_SATA_RAID | FUNCTION_RETURN_CODE_3F)
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#include <sys/ioctl.h> // _IOWR
|
||||
|
||||
/*FunctionCode*/
|
||||
#define FUNCTION_READ_RQBUFFER 0x0801
|
||||
#define FUNCTION_WRITE_WQBUFFER 0x0802
|
||||
#define FUNCTION_CLEAR_RQBUFFER 0x0803
|
||||
#define FUNCTION_CLEAR_WQBUFFER 0x0804
|
||||
#define FUNCTION_RETURN_CODE_3F 0x0806
|
||||
|
||||
/* ARECA IO CONTROL CODE*/
|
||||
#define ARCMSR_IOCTL_READ_RQBUFFER _IOWR('F', FUNCTION_READ_RQBUFFER, sSRB_BUFFER)
|
||||
#define ARCMSR_IOCTL_WRITE_WQBUFFER _IOWR('F', FUNCTION_WRITE_WQBUFFER, sSRB_BUFFER)
|
||||
#define ARCMSR_IOCTL_CLEAR_RQBUFFER _IOWR('F', FUNCTION_CLEAR_RQBUFFER, sSRB_BUFFER)
|
||||
#define ARCMSR_IOCTL_CLEAR_WQBUFFER _IOWR('F', FUNCTION_CLEAR_WQBUFFER, sSRB_BUFFER)
|
||||
#define ARCMSR_IOCTL_RETURN_CODE_3F _IOWR('F', FUNCTION_RETURN_CODE_3F, sSRB_BUFFER)
|
||||
#endif
|
||||
|
||||
// The SRB_IO_CONTROL & SRB_BUFFER structures are used to communicate(to/from) to areca driver
|
||||
typedef struct _ARCMSR_IO_HDR
|
||||
{
|
||||
unsigned int HeaderLength;
|
||||
unsigned char Signature[8];
|
||||
unsigned int Timeout;
|
||||
unsigned int ControlCode;
|
||||
unsigned int ReturnCode;
|
||||
unsigned int Length;
|
||||
} sARCMSR_IO_HDR;
|
||||
|
||||
typedef struct _SRB_BUFFER
|
||||
{
|
||||
sARCMSR_IO_HDR srbioctl;
|
||||
unsigned char ioctldatabuffer[1032]; // the buffer to put the command data to/from firmware
|
||||
} sSRB_BUFFER;
|
||||
|
||||
class generic_areca_device : virtual public smart_device
|
||||
{
|
||||
public:
|
||||
generic_areca_device(smart_interface *intf, const char *dev_name, int disknum, int encnum = 1);
|
||||
~generic_areca_device();
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// OS-dependent functions
|
||||
virtual bool arcmsr_lock() = 0;
|
||||
virtual bool arcmsr_unlock() = 0;
|
||||
virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io *iop) = 0;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// OS-independent functions
|
||||
virtual int arcmsr_command_handler(unsigned long arcmsr_cmd, unsigned char *data, int data_len);
|
||||
virtual int arcmsr_ui_handler(unsigned char *areca_packet, int areca_packet_len, unsigned char *result);
|
||||
virtual bool arcmsr_probe();
|
||||
virtual int arcmsr_get_dev_type();
|
||||
virtual int arcmsr_get_controller_type();
|
||||
virtual bool arcmsr_scsi_pass_through(scsi_cmnd_io *iop);
|
||||
virtual bool arcmsr_ata_pass_through(const ata_cmd_in &in, ata_cmd_out &out);
|
||||
|
||||
protected:
|
||||
generic_areca_device()
|
||||
: smart_device(never_called),
|
||||
m_disknum(-1), m_encnum(-1)
|
||||
{
|
||||
}
|
||||
|
||||
void set_disknum(int disknum)
|
||||
{
|
||||
m_disknum = disknum;
|
||||
}
|
||||
|
||||
void set_encnum(int encnum)
|
||||
{
|
||||
m_encnum = encnum;
|
||||
}
|
||||
|
||||
int get_disknum()
|
||||
{
|
||||
return m_disknum;
|
||||
}
|
||||
|
||||
int get_encnum()
|
||||
{
|
||||
return m_encnum;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_disknum; ///< Disk number.
|
||||
int m_encnum; ///< Enclosure number.
|
||||
};
|
||||
|
||||
// SATA(ATA) device behind Areca RAID Controller
|
||||
class areca_ata_device
|
||||
: public ata_device,
|
||||
public generic_areca_device
|
||||
{
|
||||
public:
|
||||
areca_ata_device(smart_interface *intf, const char *dev_name, int disknum, int encnum = 1);
|
||||
~areca_ata_device();
|
||||
bool arcmsr_lock() override { return true; }
|
||||
bool arcmsr_unlock() override { return true; }
|
||||
int arcmsr_do_scsi_io(struct scsi_cmnd_io * /* iop */) override
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected:
|
||||
areca_ata_device() : smart_device(never_called)
|
||||
{
|
||||
}
|
||||
virtual bool ata_pass_through(const ata_cmd_in &in, ata_cmd_out &out) override;
|
||||
};
|
||||
|
||||
// SAS(SCSI) device behind Areca RAID Controller
|
||||
class areca_scsi_device
|
||||
: public scsi_device,
|
||||
public generic_areca_device
|
||||
{
|
||||
public:
|
||||
areca_scsi_device(smart_interface *intf, const char *dev_name, int disknum, int encnum = 1);
|
||||
~areca_scsi_device();
|
||||
bool arcmsr_lock() override { return true; }
|
||||
bool arcmsr_unlock() override { return true; }
|
||||
int arcmsr_do_scsi_io(struct scsi_cmnd_io * /* iop */) override
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected:
|
||||
areca_scsi_device() : smart_device(never_called)
|
||||
{
|
||||
}
|
||||
virtual bool scsi_pass_through(scsi_cmnd_io *iop) override;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
* dev_ata_cmd_set.cpp
|
||||
*
|
||||
* Home page of code is: http://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2008-18 Christian Franke
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "atacmds.h"
|
||||
#include "dev_ata_cmd_set.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
const char *dev_ata_cmd_set_cpp_cvsid = "$Id: dev_ata_cmd_set.cpp 4760 2018-08-19 18:45:53Z chrfranke $" DEV_ATA_CMD_SET_H_CVSID;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// ata_device_with_command_set
|
||||
|
||||
// Adapter routine to implement new ATA pass through with old interface
|
||||
|
||||
bool ata_device_with_command_set::ata_pass_through(const ata_cmd_in &in, ata_cmd_out &out)
|
||||
{
|
||||
if (!ata_cmd_is_ok(in, true)) // data_out_support
|
||||
return false;
|
||||
|
||||
smart_command_set command = (smart_command_set)-1;
|
||||
int select = 0;
|
||||
char *data = (char *)in.buffer;
|
||||
char buffer[512];
|
||||
switch (in.in_regs.command)
|
||||
{
|
||||
case ATA_IDENTIFY_DEVICE:
|
||||
command = IDENTIFY;
|
||||
break;
|
||||
case ATA_IDENTIFY_PACKET_DEVICE:
|
||||
command = PIDENTIFY;
|
||||
break;
|
||||
case ATA_CHECK_POWER_MODE:
|
||||
command = CHECK_POWER_MODE;
|
||||
data = buffer;
|
||||
data[0] = 0;
|
||||
break;
|
||||
case ATA_SMART_CMD:
|
||||
switch (in.in_regs.features)
|
||||
{
|
||||
case ATA_SMART_ENABLE:
|
||||
command = ENABLE;
|
||||
break;
|
||||
case ATA_SMART_READ_VALUES:
|
||||
command = READ_VALUES;
|
||||
break;
|
||||
case ATA_SMART_READ_THRESHOLDS:
|
||||
command = READ_THRESHOLDS;
|
||||
break;
|
||||
case ATA_SMART_READ_LOG_SECTOR:
|
||||
command = READ_LOG;
|
||||
select = in.in_regs.lba_low;
|
||||
break;
|
||||
case ATA_SMART_WRITE_LOG_SECTOR:
|
||||
command = WRITE_LOG;
|
||||
select = in.in_regs.lba_low;
|
||||
break;
|
||||
case ATA_SMART_DISABLE:
|
||||
command = DISABLE;
|
||||
break;
|
||||
case ATA_SMART_STATUS:
|
||||
command = (in.out_needed.lba_high ? STATUS_CHECK : STATUS);
|
||||
break;
|
||||
case ATA_SMART_AUTO_OFFLINE:
|
||||
command = AUTO_OFFLINE;
|
||||
select = in.in_regs.sector_count;
|
||||
break;
|
||||
case ATA_SMART_AUTOSAVE:
|
||||
command = AUTOSAVE;
|
||||
select = in.in_regs.sector_count;
|
||||
break;
|
||||
case ATA_SMART_IMMEDIATE_OFFLINE:
|
||||
command = IMMEDIATE_OFFLINE;
|
||||
select = in.in_regs.lba_low;
|
||||
break;
|
||||
default:
|
||||
return set_err(ENOSYS, "Unknown SMART command");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return set_err(ENOSYS, "Non-SMART commands not implemented");
|
||||
}
|
||||
|
||||
clear_err();
|
||||
errno = 0;
|
||||
int rc = ata_command_interface(command, select, data);
|
||||
if (rc < 0)
|
||||
{
|
||||
if (!get_errno())
|
||||
set_err(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case CHECK_POWER_MODE:
|
||||
out.out_regs.sector_count = data[0];
|
||||
break;
|
||||
case STATUS_CHECK:
|
||||
switch (rc)
|
||||
{
|
||||
case 0: // Good SMART status
|
||||
out.out_regs.lba_high = 0xc2;
|
||||
out.out_regs.lba_mid = 0x4f;
|
||||
break;
|
||||
case 1: // Bad SMART status
|
||||
out.out_regs.lba_high = 0x2c;
|
||||
out.out_regs.lba_mid = 0xf4;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* dev_ata_cmd_set.h
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2008-21 Christian Franke
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef DEV_ATA_CMD_SET_H
|
||||
#define DEV_ATA_CMD_SET_H
|
||||
|
||||
#define DEV_ATA_CMD_SET_H_CVSID "$Id: dev_ata_cmd_set.h 5198 2021-02-01 20:36:02Z chrfranke $"
|
||||
|
||||
#include "atacmds.h" // smart_command_set
|
||||
#include "dev_interface.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// ata_device_with_command_set
|
||||
|
||||
/// Adapter class to implement new ATA pass through old interface.
|
||||
|
||||
class ata_device_with_command_set
|
||||
: public /*implements*/ ata_device
|
||||
{
|
||||
public:
|
||||
/// ATA pass through mapped to ata_command_interface().
|
||||
virtual bool ata_pass_through(const ata_cmd_in &in, ata_cmd_out &out) override;
|
||||
|
||||
protected:
|
||||
/// Old ATA interface called by ata_pass_through()
|
||||
virtual int ata_command_interface(smart_command_set command, int select, char *data) = 0;
|
||||
|
||||
ata_device_with_command_set()
|
||||
: smart_device(never_called) {}
|
||||
};
|
||||
|
||||
#endif // DEV_ATA_CMD_SET_H
|
|
@ -1,321 +0,0 @@
|
|||
/*
|
||||
* dev_intelliprop.cpp
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2016 Casey Biemiller <cbiemiller@intelliprop.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "atacmds.h" // ATTR_PACKED, STATIC_ASSERT, ata_debugmode
|
||||
#include "dev_interface.h"
|
||||
#include "dev_tunnelled.h"
|
||||
#include <errno.h>
|
||||
|
||||
const char *dev_intelliprop_cpp_cvsid = "$Id: dev_intelliprop.cpp 5198 2021-02-01 20:36:02Z chrfranke $";
|
||||
|
||||
// Vendor Specific log addresses
|
||||
#define LOG_C0 0xc0
|
||||
|
||||
// VS LOG MODE CONTROL BITS
|
||||
enum
|
||||
{
|
||||
IPROP_VS_LOG_MODE_CTL_AUTO_SUPPORTED = (0 << 0), // NOTE: Not supported
|
||||
IPROP_VS_LOG_MODE_CTL_MANUAL_SUPPORTED = (1 << 1),
|
||||
IPROP_VS_LOG_MODE_CTL_AUTO_ENABLED = (0 << 2), // NOTE: Not supported
|
||||
IPROP_VS_LOG_MODE_CTL_MANUAL_ENABLED = (1 << 3),
|
||||
};
|
||||
|
||||
// VS LOG PORT SETTING BITS
|
||||
enum
|
||||
{
|
||||
IPROP_VS_LOG_PORT_WRITE_ENABLE_MASK = 0xC000,
|
||||
IPROP_VS_LOG_PORT_WRITE_ENABLE_VALID = 0x8000,
|
||||
IPROP_VS_LOG_PORT_RX_DC_GAIN_MASK = 0x3000,
|
||||
IPROP_VS_LOG_PORT_RX_DC_GAIN_SHIFT = 12,
|
||||
IPROP_VS_LOG_PORT_RX_EQ_MASK = 0x0F00,
|
||||
IPROP_VS_LOG_PORT_RX_EQ_SHIFT = 8,
|
||||
IPROP_VS_LOG_PORT_TX_PREEMP_MASK = 0x00F8,
|
||||
IPROP_VS_LOG_PORT_TX_PREEMP_SHIFT = 3,
|
||||
IPROP_VS_LOG_PORT_TX_VOD_MASK = 0x0007,
|
||||
IPROP_VS_LOG_PORT_TX_VOD_SHIFT = 0,
|
||||
};
|
||||
|
||||
// This struct is used for the Vendor Specific log C0 on devices that support it.
|
||||
#pragma pack(1)
|
||||
struct iprop_internal_log
|
||||
{
|
||||
uint32_t drive_select; // Bytes - [ 3: 0] of Log C0
|
||||
uint32_t obsolete; // Bytes - [ 7: 4] of Log C0
|
||||
uint8_t mode_control; // Byte - [ 8] of Log C0
|
||||
uint8_t log_passthrough; // Byte - [ 9] of Log C0
|
||||
uint16_t tier_id; // Bytes - [ 11: 10] of Log C0
|
||||
uint32_t hw_version; // Bytes - [ 15: 12] of Log C0
|
||||
uint32_t fw_version; // Bytes - [ 19: 16] of Log C0
|
||||
uint8_t variant[8]; // Bytes - [ 27: 20] of Log C0
|
||||
uint8_t reserved[228]; // Bytes - [255: 28] of Log C0
|
||||
uint16_t port_0_settings[3]; // Bytes - [263:256] of Log C0
|
||||
uint16_t port_0_reserved;
|
||||
uint16_t port_1_settings[3]; // Bytes - [271:264] of Log C0
|
||||
uint16_t port_1_reserved;
|
||||
uint16_t port_2_settings[3]; // Bytes - [279:272] of Log C0
|
||||
uint16_t port_2_reserved;
|
||||
uint16_t port_3_settings[3]; // Bytes - [287:280] of Log C0
|
||||
uint16_t port_3_reserved;
|
||||
uint16_t port_4_settings[3]; // Bytes - [295:288] of Log C0
|
||||
uint16_t port_4_reserved;
|
||||
uint8_t reserved2[214]; // Bytes - [509:296] of Log C0
|
||||
uint16_t crc; // Bytes - [511:510] of Log C0
|
||||
} ATTR_PACKED;
|
||||
#pragma pack()
|
||||
STATIC_ASSERT(sizeof(iprop_internal_log) == 512);
|
||||
|
||||
/**
|
||||
* buffer is a pointer to a buffer of bytes, which should include data and
|
||||
* also CRC if the function is being used to check CRC
|
||||
* len is the number of bytes in the buffer (including CRC if it is present)
|
||||
* check_crc is a boolean value, set true to check an existing CRC, false
|
||||
* to calculate a new CRC
|
||||
*/
|
||||
static uint16_t iprop_crc16_1(uint8_t *buffer, uint32_t len, bool check_crc)
|
||||
{
|
||||
uint8_t crc[16];
|
||||
uint16_t crc_final = 0;
|
||||
uint8_t crc_msb;
|
||||
uint8_t data_msb;
|
||||
uint32_t total_len;
|
||||
|
||||
// Initialize CRC array
|
||||
for (uint32_t ii = 0; ii < 16; ii++)
|
||||
{
|
||||
crc[ii] = 0;
|
||||
// crc[ii] = (crc_in >> ii) & 1;
|
||||
}
|
||||
|
||||
// If calculating a new CRC, we need to pad the data with extra zeroes
|
||||
total_len = check_crc ? len : len + 2;
|
||||
|
||||
// Loop for each byte, plus extra for the CRC itself
|
||||
for (uint32_t ii = 0; ii < total_len; ii++)
|
||||
{
|
||||
uint8_t data = (ii < len) ? buffer[ii] : 0;
|
||||
|
||||
// Loop for each bit
|
||||
for (uint32_t jj = 0; jj < 8; jj++)
|
||||
{
|
||||
crc_msb = crc[15];
|
||||
data_msb = (data >> (8 - jj - 1)) & 1;
|
||||
|
||||
crc[15] = crc[14] ^ crc_msb;
|
||||
crc[14] = crc[13];
|
||||
crc[13] = crc[12];
|
||||
crc[12] = crc[11];
|
||||
crc[11] = crc[10] ^ crc_msb;
|
||||
crc[10] = crc[9];
|
||||
crc[9] = crc[8] ^ crc_msb;
|
||||
crc[8] = crc[7] ^ crc_msb;
|
||||
crc[7] = crc[6] ^ crc_msb;
|
||||
crc[6] = crc[5];
|
||||
crc[5] = crc[4] ^ crc_msb;
|
||||
crc[4] = crc[3] ^ crc_msb;
|
||||
crc[3] = crc[2];
|
||||
crc[2] = crc[1] ^ crc_msb;
|
||||
crc[1] = crc[0] ^ crc_msb;
|
||||
crc[0] = data_msb ^ crc_msb;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert CRC array to final value
|
||||
for (uint32_t ii = 0; ii < 16; ii++)
|
||||
{
|
||||
if (crc[ii] == 1)
|
||||
{
|
||||
crc_final |= (1 << ii);
|
||||
}
|
||||
else
|
||||
{
|
||||
crc_final &= ~(1 << ii);
|
||||
}
|
||||
}
|
||||
|
||||
return crc_final;
|
||||
}
|
||||
|
||||
static void iprop_dump_log_structure(struct iprop_internal_log const *const log)
|
||||
{
|
||||
pout("Dumping LOG Structure:\n");
|
||||
pout(" drive_select: 0x%08x\n", log->drive_select);
|
||||
pout(" obsolete: 0x%08x\n", log->obsolete);
|
||||
pout(" mode_control: 0x%02x\n", log->mode_control);
|
||||
pout(" log_passthrough: 0x%02x\n", log->log_passthrough);
|
||||
pout(" tier_id: 0x%04x\n", log->tier_id);
|
||||
pout(" hw_version: 0x%08x\n", log->hw_version);
|
||||
pout(" fw_version: 0x%08x\n", log->fw_version);
|
||||
pout(" variant: \"");
|
||||
for (int ii = 0; ii < 8; ii++)
|
||||
{
|
||||
pout("%c", (char)log->variant[ii]);
|
||||
}
|
||||
pout("\"\n");
|
||||
pout(" port_0_settings(Gen 1): 0x%08x\n", log->port_0_settings[0]);
|
||||
pout(" port_0_settings(Gen 2): 0x%08x\n", log->port_0_settings[1]);
|
||||
pout(" port_0_settings(Gen 3): 0x%08x\n", log->port_0_settings[2]);
|
||||
pout(" port_1_settings(Gen 1): 0x%08x\n", log->port_1_settings[0]);
|
||||
pout(" port_1_settings(Gen 2): 0x%08x\n", log->port_1_settings[1]);
|
||||
pout(" port_1_settings(Gen 3): 0x%08x\n", log->port_1_settings[2]);
|
||||
pout(" port_2_settings(Gen 1): 0x%08x\n", log->port_2_settings[0]);
|
||||
pout(" port_2_settings(Gen 2): 0x%08x\n", log->port_2_settings[1]);
|
||||
pout(" port_2_settings(Gen 3): 0x%08x\n", log->port_2_settings[2]);
|
||||
pout(" port_3_settings(Gen 1): 0x%08x\n", log->port_3_settings[0]);
|
||||
pout(" port_3_settings(Gen 2): 0x%08x\n", log->port_3_settings[1]);
|
||||
pout(" port_3_settings(Gen 3): 0x%08x\n", log->port_3_settings[2]);
|
||||
pout(" port_4_settings(Gen 1): 0x%08x\n", log->port_4_settings[0]);
|
||||
pout(" port_4_settings(Gen 2): 0x%08x\n", log->port_4_settings[1]);
|
||||
pout(" port_4_settings(Gen 3): 0x%08x\n", log->port_4_settings[2]);
|
||||
pout(" crc: 0x%04x\n", log->crc);
|
||||
pout("\n");
|
||||
}
|
||||
|
||||
static bool iprop_switch_routed_drive(ata_device *device, int drive_select)
|
||||
{
|
||||
// Declare a log page buffer and initialize it with what is on the drive currently
|
||||
iprop_internal_log write_payload;
|
||||
if (!ataReadLogExt(device, LOG_C0, 0, 0, &write_payload, 1))
|
||||
return device->set_err(EIO, "intelliprop: Initial Read Log failed: %s", device->get_errmsg());
|
||||
|
||||
// Check the returned data is good
|
||||
uint16_t const crc_check = iprop_crc16_1((uint8_t *)&write_payload,
|
||||
sizeof(struct iprop_internal_log),
|
||||
false);
|
||||
|
||||
// If this first read fails the crc check, the log can be still sent with routing information
|
||||
// as long as everything else in the log is zeroed. So there is no need to return false.
|
||||
if (crc_check != 0)
|
||||
{
|
||||
if (ata_debugmode)
|
||||
pout("Intelliprop WARNING: Received log crc(0x%04X) is invalid!\n", crc_check);
|
||||
iprop_dump_log_structure(&write_payload);
|
||||
memset(&write_payload, 0, sizeof(struct iprop_internal_log));
|
||||
}
|
||||
|
||||
// The option to read the log, even if successful, could be useful
|
||||
if (ata_debugmode)
|
||||
iprop_dump_log_structure(&write_payload);
|
||||
|
||||
// Modify the current drive select to what we were given
|
||||
write_payload.drive_select = (uint32_t)drive_select;
|
||||
if (ata_debugmode)
|
||||
pout("Intelliprop - Change to port 0x%08X.\n", write_payload.drive_select);
|
||||
write_payload.log_passthrough = 0; // TEST (Set to 1, non hydra member drive will abort --> test error handling)
|
||||
write_payload.tier_id = 0; // TEST (Set to non-zero, non hydra member drive will abort --> test error handling)
|
||||
|
||||
// Update the CRC area
|
||||
uint16_t const crc_new = iprop_crc16_1((uint8_t *)&write_payload,
|
||||
sizeof(struct iprop_internal_log) - sizeof(uint16_t),
|
||||
false);
|
||||
write_payload.crc = (crc_new >> 8) | (crc_new << 8);
|
||||
|
||||
// Check our CRC work
|
||||
uint16_t const crc_check2 = iprop_crc16_1((uint8_t *)&write_payload,
|
||||
sizeof(struct iprop_internal_log),
|
||||
false);
|
||||
if (crc_check2 != 0)
|
||||
return device->set_err(EIO, "intelliprop: Re-calculated log crc(0x%04X) is invalid!", crc_check2);
|
||||
|
||||
// Apply the Write LOG
|
||||
if (!ataWriteLogExt(device, LOG_C0, 0, &write_payload, 1))
|
||||
return device->set_err(EIO, "intelliprop: Write Log failed: %s", device->get_errmsg());
|
||||
|
||||
// Check that the Write LOG was applied
|
||||
iprop_internal_log check_payload;
|
||||
if (!ataReadLogExt(device, LOG_C0, 0, 0, &check_payload, 1))
|
||||
return device->set_err(EIO, "intelliprop: Secondary Read Log failed: %s", device->get_errmsg());
|
||||
|
||||
if (check_payload.drive_select != write_payload.drive_select)
|
||||
{
|
||||
if (ata_debugmode > 1)
|
||||
iprop_dump_log_structure(&check_payload);
|
||||
return device->set_err(EIO, "intelliprop: Current drive select val(0x%08X) is not expected(0x%08X)",
|
||||
check_payload.drive_select,
|
||||
write_payload.drive_select);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace intelliprop
|
||||
{
|
||||
|
||||
class intelliprop_device
|
||||
: public tunnelled_device<
|
||||
/*implements*/ ata_device,
|
||||
/*by using an*/ ata_device>
|
||||
{
|
||||
public:
|
||||
intelliprop_device(smart_interface *intf, unsigned phydrive, ata_device *atadev);
|
||||
|
||||
virtual ~intelliprop_device();
|
||||
|
||||
virtual bool open() override;
|
||||
|
||||
virtual bool ata_pass_through(const ata_cmd_in &in, ata_cmd_out &out) override;
|
||||
|
||||
private:
|
||||
unsigned m_phydrive;
|
||||
};
|
||||
|
||||
intelliprop_device::intelliprop_device(smart_interface *intf, unsigned phydrive, ata_device *atadev)
|
||||
: smart_device(intf, atadev->get_dev_name(), "intelliprop", "intelliprop"),
|
||||
tunnelled_device<ata_device, ata_device>(atadev),
|
||||
m_phydrive(phydrive)
|
||||
{
|
||||
set_info().info_name = strprintf("%s [intelliprop_disk_%u]", atadev->get_info_name(), phydrive);
|
||||
}
|
||||
|
||||
intelliprop_device::~intelliprop_device()
|
||||
{
|
||||
}
|
||||
|
||||
bool intelliprop_device::open()
|
||||
{
|
||||
if (!tunnelled_device<ata_device, ata_device>::open())
|
||||
return false;
|
||||
|
||||
ata_device *atadev = get_tunnel_dev();
|
||||
if (!iprop_switch_routed_drive(atadev, m_phydrive))
|
||||
{
|
||||
close();
|
||||
return set_err(atadev->get_err());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool intelliprop_device::ata_pass_through(const ata_cmd_in &in, ata_cmd_out &out)
|
||||
{
|
||||
return get_tunnel_dev()->ata_pass_through(in, out);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ata_device *smart_interface::get_intelliprop_device(const char *type, ata_device *atadev)
|
||||
{
|
||||
// Take temporary ownership of 'atadev' to delete it on error
|
||||
ata_device_auto_ptr atadev_holder(atadev);
|
||||
|
||||
unsigned phydrive = ~0;
|
||||
int n = -1;
|
||||
sscanf(type, "intelliprop,%u%n", &phydrive, &n);
|
||||
if (!(n == (int)strlen(type) && phydrive <= 3))
|
||||
{
|
||||
set_err(EINVAL, "Option '-d intelliprop,N' must have 0 <= N <= 3");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ata_device *itldev = new intelliprop::intelliprop_device(this, phydrive, atadev);
|
||||
// 'atadev' is now owned by 'itldev'
|
||||
atadev_holder.release();
|
||||
return itldev;
|
||||
}
|
|
@ -1,580 +0,0 @@
|
|||
/*
|
||||
* dev_interface.cpp
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2008-21 Christian Franke
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "dev_interface.h"
|
||||
#include "dev_tunnelled.h"
|
||||
#include "atacmds.h" // ATA_SMART_CMD/STATUS
|
||||
#include "scsicmds.h" // scsi_cmnd_io
|
||||
#include "utility.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h> // realpath()
|
||||
#include <stdexcept>
|
||||
|
||||
const char *dev_interface_cpp_cvsid = "$Id: dev_interface.cpp 5219 2021-06-04 16:39:50Z chrfranke $" DEV_INTERFACE_H_CVSID;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// smart_device
|
||||
|
||||
int smart_device::s_num_objects = 0;
|
||||
|
||||
smart_device::smart_device(smart_interface *intf, const char *dev_name,
|
||||
const char *dev_type, const char *req_type)
|
||||
: m_intf(intf), m_info(dev_name, dev_type, req_type),
|
||||
m_ata_ptr(0), m_scsi_ptr(0), m_nvme_ptr(0)
|
||||
{
|
||||
s_num_objects++;
|
||||
}
|
||||
|
||||
smart_device::smart_device(do_not_use_in_implementation_classes)
|
||||
: m_intf(0), m_ata_ptr(0), m_scsi_ptr(0), m_nvme_ptr(0)
|
||||
{
|
||||
throw std::logic_error("smart_device: wrong constructor called in implementation class");
|
||||
}
|
||||
|
||||
smart_device::~smart_device()
|
||||
{
|
||||
s_num_objects--;
|
||||
}
|
||||
|
||||
bool smart_device::is_syscall_unsup() const
|
||||
{
|
||||
if (get_errno() == ENOSYS)
|
||||
return true;
|
||||
#ifdef ENOTSUP
|
||||
if (get_errno() == ENOTSUP)
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool smart_device::set_err(int no, const char *msg, ...)
|
||||
{
|
||||
if (!msg)
|
||||
return set_err(no);
|
||||
m_err.no = no;
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
m_err.msg = vstrprintf(msg, ap);
|
||||
va_end(ap);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool smart_device::set_err(int no)
|
||||
{
|
||||
return smi()->set_err_var(&m_err, no);
|
||||
}
|
||||
|
||||
smart_device *smart_device::autodetect_open()
|
||||
{
|
||||
open();
|
||||
return this;
|
||||
}
|
||||
|
||||
bool smart_device::is_powered_down()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool smart_device::owns(const smart_device * /*dev*/) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void smart_device::release(const smart_device * /*dev*/)
|
||||
{
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// ata_device
|
||||
|
||||
ata_in_regs_48bit::ata_in_regs_48bit()
|
||||
: features_16(features, prev.features),
|
||||
sector_count_16(sector_count, prev.sector_count),
|
||||
lba_low_16(lba_low, prev.lba_low),
|
||||
lba_mid_16(lba_mid, prev.lba_mid),
|
||||
lba_high_16(lba_high, prev.lba_high),
|
||||
lba_48(lba_low, lba_mid, lba_high,
|
||||
prev.lba_low, prev.lba_mid, prev.lba_high)
|
||||
{
|
||||
}
|
||||
|
||||
ata_out_regs_48bit::ata_out_regs_48bit()
|
||||
: sector_count_16(sector_count, prev.sector_count),
|
||||
lba_low_16(lba_low, prev.lba_low),
|
||||
lba_mid_16(lba_mid, prev.lba_mid),
|
||||
lba_high_16(lba_high, prev.lba_high),
|
||||
lba_48(lba_low, lba_mid, lba_high,
|
||||
prev.lba_low, prev.lba_mid, prev.lba_high)
|
||||
{
|
||||
}
|
||||
|
||||
ata_cmd_in::ata_cmd_in()
|
||||
: direction(no_data),
|
||||
buffer(0),
|
||||
size(0)
|
||||
{
|
||||
}
|
||||
|
||||
ata_cmd_out::ata_cmd_out()
|
||||
{
|
||||
}
|
||||
|
||||
bool ata_device::ata_pass_through(const ata_cmd_in &in)
|
||||
{
|
||||
ata_cmd_out dummy;
|
||||
return ata_pass_through(in, dummy);
|
||||
}
|
||||
|
||||
bool ata_device::ata_cmd_is_supported(const ata_cmd_in &in,
|
||||
unsigned flags, const char *type /* = 0 */)
|
||||
{
|
||||
// Check DATA IN/OUT
|
||||
switch (in.direction)
|
||||
{
|
||||
case ata_cmd_in::no_data:
|
||||
break;
|
||||
case ata_cmd_in::data_in:
|
||||
break;
|
||||
case ata_cmd_in::data_out:
|
||||
break;
|
||||
default:
|
||||
return set_err(EINVAL, "Invalid data direction %d", (int)in.direction);
|
||||
}
|
||||
|
||||
// Check buffer size
|
||||
if (in.direction == ata_cmd_in::no_data)
|
||||
{
|
||||
if (in.size)
|
||||
return set_err(EINVAL, "Buffer size %u > 0 for NO DATA command", in.size);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!in.buffer)
|
||||
return set_err(EINVAL, "Buffer not set for DATA IN/OUT command");
|
||||
unsigned count = (in.in_regs.prev.sector_count << 16) | in.in_regs.sector_count;
|
||||
// TODO: Add check for sector count == 0
|
||||
if (count * 512 != in.size)
|
||||
return set_err(EINVAL, "Sector count %u does not match buffer size %u", count, in.size);
|
||||
}
|
||||
|
||||
// Check features
|
||||
const char *errmsg = 0;
|
||||
if (in.direction == ata_cmd_in::data_out && !(flags & supports_data_out))
|
||||
errmsg = "DATA OUT ATA commands not implemented";
|
||||
else if (in.out_needed.is_set() && !(flags & supports_output_regs) && !(in.in_regs.command == ATA_SMART_CMD && in.in_regs.features == ATA_SMART_STATUS && (flags & supports_smart_status)))
|
||||
errmsg = "Read of ATA output registers not implemented";
|
||||
else if (!(in.size == 0 || in.size == 512) && !(flags & supports_multi_sector))
|
||||
errmsg = "Multi-sector ATA commands not implemented";
|
||||
else if (in.in_regs.is_48bit_cmd() && !(flags & (supports_48bit_hi_null | supports_48bit)))
|
||||
errmsg = "48-bit ATA commands not implemented";
|
||||
else if (in.in_regs.is_real_48bit_cmd() && !(flags & supports_48bit))
|
||||
errmsg = "48-bit ATA commands not fully implemented";
|
||||
|
||||
if (errmsg)
|
||||
return set_err(ENOSYS, "%s%s%s%s", errmsg,
|
||||
(type ? " [" : ""), (type ? type : ""), (type ? "]" : ""));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ata_device::ata_identify_is_cached() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// scsi_device
|
||||
|
||||
bool scsi_device::scsi_pass_through_and_check(scsi_cmnd_io *iop,
|
||||
const char *msg)
|
||||
{
|
||||
// Provide sense buffer
|
||||
unsigned char sense[32] = {
|
||||
0,
|
||||
};
|
||||
iop->sensep = sense;
|
||||
iop->max_sense_len = sizeof(sense);
|
||||
iop->timeout = SCSI_TIMEOUT_DEFAULT;
|
||||
|
||||
// Run cmd
|
||||
if (!scsi_pass_through(iop))
|
||||
{
|
||||
if (scsi_debugmode > 0)
|
||||
pout("%sscsi_pass_through() failed, errno=%d [%s]\n",
|
||||
msg, get_errno(), get_errmsg());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check sense
|
||||
scsi_sense_disect sinfo;
|
||||
scsi_do_sense_disect(iop, &sinfo);
|
||||
int err = scsiSimpleSenseFilter(&sinfo);
|
||||
if (err)
|
||||
{
|
||||
if (scsi_debugmode > 0)
|
||||
pout("%sscsi error: %s\n", msg, scsiErrString(err));
|
||||
return set_err(EIO, "scsi error %s", scsiErrString(err));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// nvme_device
|
||||
|
||||
bool nvme_device::set_nvme_err(nvme_cmd_out &out, unsigned status, const char *msg /* = 0 */)
|
||||
{
|
||||
if (!status)
|
||||
throw std::logic_error("nvme_device: set_nvme_err() called with status=0");
|
||||
|
||||
out.status = status;
|
||||
out.status_valid = true;
|
||||
return set_err(EIO, "%sNVMe Status 0x%02x", (msg ? msg : ""), status);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// tunnelled_device_base
|
||||
|
||||
tunnelled_device_base::tunnelled_device_base(smart_device *tunnel_dev)
|
||||
: smart_device(never_called),
|
||||
m_tunnel_base_dev(tunnel_dev)
|
||||
{
|
||||
}
|
||||
|
||||
tunnelled_device_base::~tunnelled_device_base()
|
||||
{
|
||||
delete m_tunnel_base_dev;
|
||||
}
|
||||
|
||||
bool tunnelled_device_base::is_open() const
|
||||
{
|
||||
return (m_tunnel_base_dev && m_tunnel_base_dev->is_open());
|
||||
}
|
||||
|
||||
bool tunnelled_device_base::open()
|
||||
{
|
||||
if (!m_tunnel_base_dev)
|
||||
return set_err(ENOSYS);
|
||||
if (!m_tunnel_base_dev->open())
|
||||
return set_err(m_tunnel_base_dev->get_err());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tunnelled_device_base::close()
|
||||
{
|
||||
if (!m_tunnel_base_dev)
|
||||
return true;
|
||||
if (!m_tunnel_base_dev->close())
|
||||
return set_err(m_tunnel_base_dev->get_err());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tunnelled_device_base::owns(const smart_device *dev) const
|
||||
{
|
||||
return (m_tunnel_base_dev && (m_tunnel_base_dev == dev));
|
||||
}
|
||||
|
||||
void tunnelled_device_base::release(const smart_device *dev)
|
||||
{
|
||||
if (m_tunnel_base_dev == dev)
|
||||
m_tunnel_base_dev = 0;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// smart_interface
|
||||
|
||||
// Pointer to (usually singleton) interface object returned by ::smi()
|
||||
smart_interface *smart_interface::s_instance;
|
||||
|
||||
std::string smart_interface::get_os_version_str()
|
||||
{
|
||||
return SMARTMONTOOLS_BUILD_HOST;
|
||||
}
|
||||
|
||||
std::string smart_interface::get_valid_dev_types_str()
|
||||
{
|
||||
// default
|
||||
std::string s =
|
||||
"ata, scsi[+TYPE], nvme[,NSID], sat[,auto][,N][+TYPE], usbcypress[,X], "
|
||||
"usbjmicron[,p][,x][,N], usbprolific, usbsunplus, sntasmedia, sntjmicron[,NSID], "
|
||||
"sntrealtek, intelliprop,N[+TYPE], jmb39x[-q],N[,sLBA][,force][+TYPE], "
|
||||
"jms56x,N[,sLBA][,force][+TYPE]";
|
||||
// append custom
|
||||
std::string s2 = get_valid_custom_dev_types_str();
|
||||
if (!s2.empty())
|
||||
{
|
||||
s += ", ";
|
||||
s += s2;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string smart_interface::get_app_examples(const char * /*appname*/)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
bool smart_interface::disable_system_auto_standby(bool /*disable*/)
|
||||
{
|
||||
return set_err(ENOSYS);
|
||||
}
|
||||
|
||||
bool smart_interface::set_err(int no, const char *msg, ...)
|
||||
{
|
||||
if (!msg)
|
||||
return set_err(no);
|
||||
m_err.no = no;
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
m_err.msg = vstrprintf(msg, ap);
|
||||
va_end(ap);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool smart_interface::set_err(int no)
|
||||
{
|
||||
return set_err_var(&m_err, no);
|
||||
}
|
||||
|
||||
bool smart_interface::set_err_var(smart_device::error_info *err, int no)
|
||||
{
|
||||
err->no = no;
|
||||
err->msg = get_msg_for_errno(no);
|
||||
if (err->msg.empty() && no != 0)
|
||||
err->msg = strprintf("Unknown error %d", no);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *smart_interface::get_msg_for_errno(int no)
|
||||
{
|
||||
return strerror(no);
|
||||
}
|
||||
|
||||
std::string smart_interface::get_unique_dev_name(const char *name, const char *type) const
|
||||
{
|
||||
std::string unique_name;
|
||||
#if defined(HAVE_UNISTD_H) && !defined(_WIN32) && !defined(__OS2__)
|
||||
char *p = realpath(name, (char *)0); // nullptr requires POSIX.1.2008 compatibility
|
||||
if (p)
|
||||
{
|
||||
unique_name = p;
|
||||
free(p);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
unique_name = name;
|
||||
|
||||
if (*type && is_raid_dev_type(type))
|
||||
{
|
||||
// -d TYPE options must match if RAID drive number is specified
|
||||
unique_name += " [";
|
||||
unique_name += type;
|
||||
unique_name += ']';
|
||||
}
|
||||
return unique_name;
|
||||
}
|
||||
|
||||
bool smart_interface::is_raid_dev_type(const char *type) const
|
||||
{
|
||||
if (!strchr(type, ','))
|
||||
return false;
|
||||
if (str_starts_with(type, "sat,"))
|
||||
return false;
|
||||
int i;
|
||||
if (sscanf(type, "%*[^,],%d", &i) != 1)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Default device factory
|
||||
|
||||
smart_device *smart_interface::get_smart_device(const char *name, const char *type)
|
||||
{
|
||||
clear_err();
|
||||
|
||||
// Call platform specific autodetection if no device type specified
|
||||
smart_device *dev;
|
||||
if (!type || !*type)
|
||||
{
|
||||
dev = autodetect_smart_device(name);
|
||||
if (!dev && !get_errno())
|
||||
set_err(EINVAL, "Unable to detect device type");
|
||||
return dev;
|
||||
}
|
||||
|
||||
// First check for platform specific device types
|
||||
dev = get_custom_smart_device(name, type);
|
||||
if (dev || get_errno())
|
||||
return dev;
|
||||
|
||||
if (!strcmp(type, "ata"))
|
||||
dev = get_ata_device(name, type);
|
||||
else if (!strcmp(type, "scsi"))
|
||||
dev = get_scsi_device(name, type);
|
||||
|
||||
else if (str_starts_with(type, "nvme"))
|
||||
{
|
||||
int n1 = -1, n2 = -1, len = strlen(type);
|
||||
unsigned nsid = 0; // invalid namespace id -> use default
|
||||
sscanf(type, "nvme%n,0x%x%n", &n1, &nsid, &n2);
|
||||
if (!(n1 == len || n2 == len))
|
||||
{
|
||||
set_err(EINVAL, "Invalid NVMe namespace id in '%s'", type);
|
||||
return 0;
|
||||
}
|
||||
dev = get_nvme_device(name, type, nsid);
|
||||
}
|
||||
// TODO: Unify handling of '-d TYPE...+BASETYPE...'
|
||||
else if ((str_starts_with(type, "sat") && (!type[3] || strchr(",+", type[3]))) || str_starts_with(type, "scsi+") || str_starts_with(type, "usb"))
|
||||
{
|
||||
// Split "sat...+base..." -> ("sat...", "base...")
|
||||
unsigned satlen = strcspn(type, "+");
|
||||
std::string sattype(type, satlen);
|
||||
const char *basetype = (type[satlen] ? type + satlen + 1 : "");
|
||||
// Recurse to allocate base device, default is standard SCSI
|
||||
if (!*basetype)
|
||||
basetype = "scsi";
|
||||
smart_device_auto_ptr basedev(get_smart_device(name, basetype));
|
||||
if (!basedev)
|
||||
{
|
||||
set_err(EINVAL, "Type '%s+...': %s", sattype.c_str(), get_errmsg());
|
||||
return 0;
|
||||
}
|
||||
// Result must be SCSI
|
||||
if (!basedev->is_scsi())
|
||||
{
|
||||
set_err(EINVAL, "Type '%s+...': Device type '%s' is not SCSI", sattype.c_str(), basetype);
|
||||
return 0;
|
||||
}
|
||||
// Attach SAT tunnel
|
||||
return get_sat_device(sattype.c_str(), basedev.release()->to_scsi());
|
||||
}
|
||||
|
||||
else if (str_starts_with(type, "snt"))
|
||||
{
|
||||
smart_device_auto_ptr basedev(get_smart_device(name, "scsi"));
|
||||
if (!basedev)
|
||||
{
|
||||
set_err(EINVAL, "Type '%s': %s", type, get_errmsg());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return get_snt_device(type, basedev.release()->to_scsi());
|
||||
}
|
||||
|
||||
else if (str_starts_with(type, "jmb39x") || str_starts_with(type, "jms56x"))
|
||||
{
|
||||
// Split "jmb39x...+base..." -> ("jmb39x...", "base...")
|
||||
unsigned jmblen = strcspn(type, "+");
|
||||
std::string jmbtype(type, jmblen);
|
||||
const char *basetype = (type[jmblen] ? type + jmblen + 1 : "");
|
||||
// Recurse to allocate base device, default is standard SCSI
|
||||
if (!*basetype)
|
||||
basetype = "scsi";
|
||||
smart_device_auto_ptr basedev(get_smart_device(name, basetype));
|
||||
if (!basedev)
|
||||
{
|
||||
set_err(EINVAL, "Type '%s+...': %s", jmbtype.c_str(), get_errmsg());
|
||||
return 0;
|
||||
}
|
||||
// Attach JMB39x tunnel
|
||||
return get_jmb39x_device(jmbtype.c_str(), basedev.release());
|
||||
}
|
||||
|
||||
else if (str_starts_with(type, "intelliprop"))
|
||||
{
|
||||
// Split "intelliprop...+base..." -> ("intelliprop...", "base...")
|
||||
unsigned itllen = strcspn(type, "+");
|
||||
std::string itltype(type, itllen);
|
||||
const char *basetype = (type[itllen] ? type + itllen + 1 : "");
|
||||
// Recurse to allocate base device, default is standard ATA
|
||||
if (!*basetype)
|
||||
basetype = "ata";
|
||||
smart_device_auto_ptr basedev(get_smart_device(name, basetype));
|
||||
if (!basedev)
|
||||
{
|
||||
set_err(EINVAL, "Type '%s': %s", type, get_errmsg());
|
||||
return 0;
|
||||
}
|
||||
// Result must be ATA
|
||||
if (!basedev->is_ata())
|
||||
{
|
||||
set_err(EINVAL, "Type '%s': Device type '%s' is not ATA", type, basetype);
|
||||
return 0;
|
||||
}
|
||||
return get_intelliprop_device(itltype.c_str(), basedev.release()->to_ata());
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
set_err(EINVAL, "Unknown device type '%s'", type);
|
||||
return 0;
|
||||
}
|
||||
if (!dev && !get_errno())
|
||||
set_err(EINVAL, "Not a device of type '%s'", type);
|
||||
return dev;
|
||||
}
|
||||
|
||||
bool smart_interface::scan_smart_devices(smart_device_list & /*devlist*/,
|
||||
const char * /*type*/, const char * /*pattern*/ /* = 0 */)
|
||||
{
|
||||
return set_err(ENOSYS);
|
||||
}
|
||||
|
||||
bool smart_interface::scan_smart_devices(smart_device_list &devlist,
|
||||
const smart_devtype_list &types, const char *pattern /* = 0 */)
|
||||
{
|
||||
unsigned n = types.size();
|
||||
if (n == 0)
|
||||
return scan_smart_devices(devlist, (const char *)0, pattern);
|
||||
if (n == 1)
|
||||
return scan_smart_devices(devlist, types.front().c_str(), pattern);
|
||||
|
||||
for (unsigned i = 0; i < n; i++)
|
||||
{
|
||||
smart_device_list tmplist;
|
||||
if (!scan_smart_devices(tmplist, types[i].c_str(), pattern))
|
||||
return false;
|
||||
devlist.append(tmplist);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nvme_device *smart_interface::get_nvme_device(const char * /*name*/, const char * /*type*/, unsigned /*nsid*/)
|
||||
{
|
||||
set_err(ENOSYS, "NVMe devices are not supported in this version of smartmontools");
|
||||
return 0;
|
||||
}
|
||||
|
||||
smart_device *smart_interface::get_custom_smart_device(const char * /*name*/, const char * /*type*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string smart_interface::get_valid_custom_dev_types_str()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
smart_device *smart_interface::get_scsi_passthrough_device(const char *type, scsi_device *scsidev)
|
||||
{
|
||||
if (!strncmp(type, "snt", 3))
|
||||
{
|
||||
return get_snt_device(type, scsidev);
|
||||
}
|
||||
|
||||
return get_sat_device(type, scsidev);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
* dev_tunnelled.h
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2008-21 Christian Franke
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef DEV_TUNNELLED_H
|
||||
#define DEV_TUNNELLED_H
|
||||
|
||||
#define DEV_TUNNELLED_H_CVSID "$Id: dev_tunnelled.h 5198 2021-02-01 20:36:02Z chrfranke $"
|
||||
|
||||
#include "dev_interface.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// tunnelled_device_base
|
||||
|
||||
/// Common functionality for all tunnelled_device classes.
|
||||
|
||||
class tunnelled_device_base
|
||||
: virtual public /*implements*/ smart_device
|
||||
{
|
||||
protected:
|
||||
explicit tunnelled_device_base(smart_device *tunnel_dev);
|
||||
|
||||
public:
|
||||
virtual ~tunnelled_device_base();
|
||||
|
||||
virtual bool is_open() const override;
|
||||
|
||||
virtual bool open() override;
|
||||
|
||||
virtual bool close() override;
|
||||
|
||||
virtual bool owns(const smart_device *dev) const override;
|
||||
|
||||
virtual void release(const smart_device *dev) override;
|
||||
|
||||
private:
|
||||
smart_device *m_tunnel_base_dev;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// tunnelled_device
|
||||
|
||||
/// Implement a device by tunneling through another device
|
||||
|
||||
template <class BaseDev, class TunnelDev>
|
||||
class tunnelled_device
|
||||
: public BaseDev,
|
||||
public tunnelled_device_base
|
||||
{
|
||||
public:
|
||||
typedef TunnelDev tunnel_device_type;
|
||||
|
||||
protected:
|
||||
explicit tunnelled_device(tunnel_device_type *tunnel_dev)
|
||||
: smart_device(smart_device::never_called),
|
||||
tunnelled_device_base(tunnel_dev),
|
||||
m_tunnel_dev(tunnel_dev)
|
||||
{
|
||||
}
|
||||
|
||||
// For nvme_device
|
||||
explicit tunnelled_device(tunnel_device_type *tunnel_dev, unsigned nsid)
|
||||
: smart_device(smart_device::never_called),
|
||||
BaseDev(nsid),
|
||||
tunnelled_device_base(tunnel_dev),
|
||||
m_tunnel_dev(tunnel_dev)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void release(const smart_device *dev) override
|
||||
{
|
||||
if (m_tunnel_dev == dev)
|
||||
m_tunnel_dev = 0;
|
||||
tunnelled_device_base::release(dev);
|
||||
}
|
||||
|
||||
tunnel_device_type *get_tunnel_dev()
|
||||
{
|
||||
return m_tunnel_dev;
|
||||
}
|
||||
|
||||
const tunnel_device_type *get_tunnel_dev() const
|
||||
{
|
||||
return m_tunnel_dev;
|
||||
}
|
||||
|
||||
private:
|
||||
tunnel_device_type *m_tunnel_dev;
|
||||
};
|
||||
|
||||
#endif // DEV_TUNNELLED_H
|
File diff suppressed because it is too large
Load Diff
|
@ -1,729 +0,0 @@
|
|||
/*
|
||||
* json.cpp
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2017-22 Christian Franke
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#define __STDC_FORMAT_MACROS 1 // enable PRI* for C++
|
||||
|
||||
#include "json.h"
|
||||
|
||||
const char *json_cvsid = "$Id: json.cpp 5292 2022-01-06 17:13:25Z chrfranke $" JSON_H_CVSID;
|
||||
|
||||
#include "sg_unaligned.h"
|
||||
#include "utility.h" // regular_expression, uint128_*()
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdexcept>
|
||||
|
||||
static void jassert_failed(int line, const char *expr)
|
||||
{
|
||||
char msg[128];
|
||||
// Avoid __FILE__ as it may break reproducible builds
|
||||
snprintf(msg, sizeof(msg), "json.cpp(%d): Assertion failed: %s", line, expr);
|
||||
throw std::logic_error(msg);
|
||||
}
|
||||
|
||||
#define jassert(expr) (!(expr) ? jassert_failed(__LINE__, #expr) : (void)0)
|
||||
|
||||
std::string json::str2key(const char *str)
|
||||
{
|
||||
std::string key = str;
|
||||
for (char &c : key)
|
||||
{
|
||||
if (('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || c == '_')
|
||||
continue;
|
||||
if ('A' <= c && c <= 'Z')
|
||||
c += 'a' - 'A';
|
||||
else
|
||||
c = '_';
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
json::ref::ref(json &js)
|
||||
: m_js(js)
|
||||
{
|
||||
}
|
||||
|
||||
json::ref::ref(json &js, const char *keystr)
|
||||
: m_js(js)
|
||||
{
|
||||
jassert(keystr && *keystr);
|
||||
m_path.push_back(node_info(keystr));
|
||||
}
|
||||
|
||||
json::ref::ref(const ref &base, const char *keystr)
|
||||
: m_js(base.m_js), m_path(base.m_path)
|
||||
{
|
||||
jassert(keystr && *keystr);
|
||||
m_path.push_back(node_info(keystr));
|
||||
}
|
||||
|
||||
json::ref::ref(const ref &base, int index)
|
||||
: m_js(base.m_js), m_path(base.m_path)
|
||||
{
|
||||
jassert(0 <= index && index < 10000); // Limit: large arrays not supported
|
||||
m_path.push_back(node_info(index));
|
||||
}
|
||||
|
||||
json::ref::ref(const ref &base, const char * /*dummy*/, const char *key_suffix)
|
||||
: m_js(base.m_js), m_path(base.m_path)
|
||||
{
|
||||
int n = (int)m_path.size(), i;
|
||||
for (i = n; --i >= 0;)
|
||||
{
|
||||
std::string &base_key = m_path[i].key;
|
||||
if (base_key.empty())
|
||||
continue; // skip array
|
||||
base_key += key_suffix;
|
||||
break;
|
||||
}
|
||||
jassert(i >= 0); // Limit: top level element must be an object
|
||||
}
|
||||
|
||||
json::ref::~ref()
|
||||
{
|
||||
}
|
||||
|
||||
void json::ref::operator=(bool value)
|
||||
{
|
||||
m_js.set_bool(m_path, value);
|
||||
}
|
||||
|
||||
void json::ref::operator=(long long value)
|
||||
{
|
||||
m_js.set_int64(m_path, (int64_t)value);
|
||||
}
|
||||
|
||||
void json::ref::operator=(unsigned long long value)
|
||||
{
|
||||
m_js.set_uint64(m_path, (uint64_t)value);
|
||||
}
|
||||
|
||||
void json::ref::operator=(int value)
|
||||
{
|
||||
operator=((long long)value);
|
||||
}
|
||||
|
||||
void json::ref::operator=(unsigned value)
|
||||
{
|
||||
operator=((unsigned long long)value);
|
||||
}
|
||||
|
||||
void json::ref::operator=(long value)
|
||||
{
|
||||
operator=((long long)value);
|
||||
}
|
||||
|
||||
void json::ref::operator=(unsigned long value)
|
||||
{
|
||||
operator=((unsigned long long)value);
|
||||
}
|
||||
|
||||
void json::ref::operator=(const char *value)
|
||||
{
|
||||
m_js.set_cstring(m_path, value);
|
||||
}
|
||||
|
||||
void json::ref::operator=(const std::string &value)
|
||||
{
|
||||
m_js.set_string(m_path, value);
|
||||
}
|
||||
|
||||
void json::ref::set_uint128(uint64_t value_hi, uint64_t value_lo)
|
||||
{
|
||||
if (!value_hi)
|
||||
operator=((unsigned long long)value_lo);
|
||||
else
|
||||
m_js.set_uint128(m_path, value_hi, value_lo);
|
||||
}
|
||||
|
||||
bool json::ref::set_if_safe_uint64(uint64_t value)
|
||||
{
|
||||
if (!is_safe_uint(value))
|
||||
return false;
|
||||
operator=((unsigned long long)value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool json::ref::set_if_safe_uint128(uint64_t value_hi, uint64_t value_lo)
|
||||
{
|
||||
if (value_hi)
|
||||
return false;
|
||||
return set_if_safe_uint64(value_lo);
|
||||
}
|
||||
|
||||
bool json::ref::set_if_safe_le128(const void *pvalue)
|
||||
{
|
||||
return set_if_safe_uint128(sg_get_unaligned_le64((const uint8_t *)pvalue + 8),
|
||||
sg_get_unaligned_le64(pvalue));
|
||||
}
|
||||
|
||||
void json::ref::set_unsafe_uint64(uint64_t value)
|
||||
{
|
||||
// Output as number "KEY"
|
||||
operator=((unsigned long long)value);
|
||||
if (!m_js.m_verbose && is_safe_uint(value))
|
||||
return;
|
||||
// Output as string "KEY_s"
|
||||
char s[32];
|
||||
snprintf(s, sizeof(s), "%" PRIu64, value);
|
||||
with_suffix("_s") = s;
|
||||
}
|
||||
|
||||
void json::ref::set_unsafe_uint128(uint64_t value_hi, uint64_t value_lo)
|
||||
{
|
||||
if (!m_js.m_verbose && !value_hi)
|
||||
set_unsafe_uint64(value_lo);
|
||||
else
|
||||
{
|
||||
// Output as number "KEY", string "KEY_s" and LE byte array "KEY_le[]"
|
||||
m_js.m_uint128_output = true;
|
||||
set_uint128(value_hi, value_lo);
|
||||
char s[64];
|
||||
with_suffix("_s") = uint128_hilo_to_str(s, value_hi, value_lo);
|
||||
ref le = with_suffix("_le");
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
uint64_t v = (value_lo >> (i << 3));
|
||||
if (!v && !value_hi)
|
||||
break;
|
||||
le[i] = v & 0xff;
|
||||
}
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
uint64_t v = value_hi >> (i << 3);
|
||||
if (!v)
|
||||
break;
|
||||
le[8 + i] = v & 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void json::ref::set_unsafe_le128(const void *pvalue)
|
||||
{
|
||||
set_unsafe_uint128(sg_get_unaligned_le64((const uint8_t *)pvalue + 8),
|
||||
sg_get_unaligned_le64(pvalue));
|
||||
}
|
||||
|
||||
void json::ref::operator+=(std::initializer_list<initlist_key_value_pair> ilist)
|
||||
{
|
||||
for (const initlist_key_value_pair &kv : ilist)
|
||||
{
|
||||
jassert(kv.keystr && *kv.keystr);
|
||||
switch (kv.value.type)
|
||||
{
|
||||
default:
|
||||
operator[](kv.keystr) = kv.value;
|
||||
break;
|
||||
case nt_object:
|
||||
operator[](kv.keystr) += kv.object;
|
||||
break;
|
||||
case nt_array:
|
||||
operator[](kv.keystr) += kv.array;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void json::ref::operator+=(std::initializer_list<initlist_value> ilist)
|
||||
{
|
||||
int i = 0;
|
||||
for (const initlist_value &v : ilist)
|
||||
operator[](i++) = v;
|
||||
}
|
||||
|
||||
json::node::node()
|
||||
{
|
||||
}
|
||||
|
||||
json::node::node(const std::string &key_)
|
||||
: key(key_)
|
||||
{
|
||||
}
|
||||
|
||||
json::node::~node()
|
||||
{
|
||||
}
|
||||
|
||||
json::node::const_iterator::const_iterator(const json::node *node_p, bool sorted)
|
||||
: m_node_p(node_p),
|
||||
m_use_map(sorted && node_p->type == nt_object)
|
||||
{
|
||||
if (m_use_map)
|
||||
m_key_iter = node_p->key2index.begin();
|
||||
}
|
||||
|
||||
bool json::node::const_iterator::at_end() const
|
||||
{
|
||||
if (m_use_map)
|
||||
return (m_key_iter == m_node_p->key2index.end());
|
||||
else
|
||||
return (m_child_idx >= m_node_p->childs.size());
|
||||
}
|
||||
|
||||
unsigned json::node::const_iterator::array_index() const
|
||||
{
|
||||
jassert(m_node_p->type == nt_array);
|
||||
return m_child_idx;
|
||||
}
|
||||
|
||||
void json::node::const_iterator::operator++()
|
||||
{
|
||||
if (m_use_map)
|
||||
++m_key_iter;
|
||||
else
|
||||
++m_child_idx;
|
||||
}
|
||||
|
||||
const json::node *json::node::const_iterator::operator*() const
|
||||
{
|
||||
if (m_use_map)
|
||||
return m_node_p->childs[m_key_iter->second].get();
|
||||
else
|
||||
return m_node_p->childs[m_child_idx].get();
|
||||
}
|
||||
|
||||
json::node *json::find_or_create_node(const json::node_path &path, node_type type)
|
||||
{
|
||||
node *p = &m_root_node;
|
||||
for (unsigned i = 0; i < path.size(); i++)
|
||||
{
|
||||
const node_info &pi = path[i];
|
||||
if (!pi.key.empty())
|
||||
{
|
||||
// Object
|
||||
if (p->type == nt_unset)
|
||||
p->type = nt_object;
|
||||
else
|
||||
jassert(p->type == nt_object); // Limit: type change not supported
|
||||
// Existing or new object element?
|
||||
node::keymap::iterator ni = p->key2index.find(pi.key);
|
||||
node *p2;
|
||||
if (ni != p->key2index.end())
|
||||
{
|
||||
// Object element exists
|
||||
p2 = p->childs[ni->second].get();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create new object element
|
||||
p->key2index[pi.key] = (unsigned)p->childs.size();
|
||||
p->childs.push_back(std::unique_ptr<node>(p2 = new node(pi.key)));
|
||||
}
|
||||
jassert(p2 && p2->key == pi.key);
|
||||
p = p2;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// Array
|
||||
if (p->type == nt_unset)
|
||||
p->type = nt_array;
|
||||
else
|
||||
jassert(p->type == nt_array); // Limit: type change not supported
|
||||
node *p2;
|
||||
// Existing or new array element?
|
||||
if (pi.index < (int)p->childs.size())
|
||||
{
|
||||
// Array index exists
|
||||
p2 = p->childs[pi.index].get();
|
||||
if (!p2) // Already created ?
|
||||
p->childs[pi.index].reset(p2 = new node);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Grow array, fill gap, create new element
|
||||
p->childs.resize(pi.index + 1);
|
||||
p->childs[pi.index].reset(p2 = new node);
|
||||
}
|
||||
jassert(p2 && p2->key.empty());
|
||||
p = p2;
|
||||
}
|
||||
}
|
||||
|
||||
if (p->type == nt_unset || (nt_int <= p->type && p->type <= nt_uint128 && nt_int <= type && type <= nt_uint128))
|
||||
p->type = type;
|
||||
else
|
||||
jassert(p->type == type); // Limit: type change not supported
|
||||
return p;
|
||||
}
|
||||
|
||||
void json::set_bool(const node_path &path, bool value)
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
find_or_create_node(path, nt_bool)->intval = (value ? 1 : 0);
|
||||
}
|
||||
|
||||
void json::set_int64(const node_path &path, int64_t value)
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
find_or_create_node(path, nt_int)->intval = (uint64_t)value;
|
||||
}
|
||||
|
||||
void json::set_uint64(const node_path &path, uint64_t value)
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
find_or_create_node(path, nt_uint)->intval = value;
|
||||
}
|
||||
|
||||
void json::set_uint128(const node_path &path, uint64_t value_hi, uint64_t value_lo)
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
node *p = find_or_create_node(path, nt_uint128);
|
||||
p->intval_hi = value_hi;
|
||||
p->intval = value_lo;
|
||||
}
|
||||
|
||||
void json::set_cstring(const node_path &path, const char *value)
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
jassert(value != nullptr); // Limit: nullptr not supported
|
||||
find_or_create_node(path, nt_string)->strval = value;
|
||||
}
|
||||
|
||||
void json::set_string(const node_path &path, const std::string &value)
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
find_or_create_node(path, nt_string)->strval = value;
|
||||
}
|
||||
|
||||
void json::set_initlist_value(const node_path &path, const initlist_value &val)
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
node *p = find_or_create_node(path, val.type);
|
||||
switch (p->type)
|
||||
{
|
||||
case nt_bool:
|
||||
case nt_int:
|
||||
case nt_uint:
|
||||
p->intval = val.intval;
|
||||
break;
|
||||
case nt_string:
|
||||
p->strval = val.strval;
|
||||
break;
|
||||
default:
|
||||
jassert(false);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_quoted_string(FILE *f, const char *s)
|
||||
{
|
||||
putc('"', f);
|
||||
for (int i = 0; s[i]; i++)
|
||||
{
|
||||
char c = s[i];
|
||||
if (c == '"' || c == '\\')
|
||||
putc('\\', f);
|
||||
else if (c == '\t')
|
||||
{
|
||||
putc('\\', f);
|
||||
c = 't';
|
||||
}
|
||||
else if ((unsigned char)c < ' ')
|
||||
c = '?'; // Not ' '-'~', '\t' or UTF-8
|
||||
putc(c, f);
|
||||
}
|
||||
putc('"', f);
|
||||
}
|
||||
|
||||
static char yaml_string_needs_quotes(const char *s)
|
||||
{
|
||||
if (!*s)
|
||||
return '\''; // empty string
|
||||
bool need = false;
|
||||
char quotes = '\'';
|
||||
for (int i = 0; s[i]; i++)
|
||||
{
|
||||
char c = s[i];
|
||||
if (!(' ' <= c && c <= '~'))
|
||||
return '"'; // non-ascii char
|
||||
if (('0' <= c && c <= '9') || ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || c == '_')
|
||||
continue;
|
||||
if (c == '\'') // if string contains any single quote
|
||||
quotes = '"'; // use double quotes
|
||||
if (i == 0)
|
||||
need = true; // space or special char except '_' at BOL
|
||||
else if (c == ' ' && (s[i - 1] == ':' || s[i + 1] == '#'))
|
||||
need = true; // ": " or " #"
|
||||
else if ((c == ' ' || c == ':') && !s[i + 1])
|
||||
need = true; // space or : at EOL
|
||||
}
|
||||
if (need)
|
||||
return quotes;
|
||||
|
||||
static const regular_expression special(
|
||||
"[0-9]+[,0-9]*(\\.[0-9]*)?([eE][-+]?[0-9]+)?|" // decimal ('^[-+.]' handled above)
|
||||
"0x[0-7A-Fa-f]+|" // hex
|
||||
"[Ff][Aa][Ll][Ss][Ee]|[Tt][Rr][Uu][Ee]|[Nn][Oo]|[Yy][Ee][Ss]|" // boolean
|
||||
"[Nn][Uu][Ll][Ll]" // null
|
||||
);
|
||||
if (special.full_match(s))
|
||||
return quotes; // special token
|
||||
return 0; // none of the above
|
||||
}
|
||||
|
||||
void json::print_json(FILE *f, bool pretty, bool sorted, const node *p, int level)
|
||||
{
|
||||
bool is_obj = (p->type == nt_object);
|
||||
switch (p->type)
|
||||
{
|
||||
case nt_object:
|
||||
case nt_array:
|
||||
putc((is_obj ? '{' : '['), f);
|
||||
if (!p->childs.empty())
|
||||
{
|
||||
bool first = true;
|
||||
for (node::const_iterator it(p, sorted); !it.at_end(); ++it)
|
||||
{
|
||||
if (!first)
|
||||
putc(',', f);
|
||||
if (pretty)
|
||||
fprintf(f, "\n%*s", (level + 1) * 2, "");
|
||||
const node *p2 = *it;
|
||||
if (!p2)
|
||||
{
|
||||
// Unset element of sparse array
|
||||
jassert(!is_obj);
|
||||
fputs("null", f);
|
||||
}
|
||||
else
|
||||
{
|
||||
jassert(is_obj == !p2->key.empty());
|
||||
if (is_obj)
|
||||
fprintf(f, "\"%s\":%s", p2->key.c_str(), (pretty ? " " : ""));
|
||||
// Recurse
|
||||
print_json(f, pretty, sorted, p2, level + 1);
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
if (pretty)
|
||||
fprintf(f, "\n%*s", level * 2, "");
|
||||
}
|
||||
putc((is_obj ? '}' : ']'), f);
|
||||
break;
|
||||
|
||||
case nt_bool:
|
||||
fputs((p->intval ? "true" : "false"), f);
|
||||
break;
|
||||
|
||||
case nt_int:
|
||||
fprintf(f, "%" PRId64, (int64_t)p->intval);
|
||||
break;
|
||||
|
||||
case nt_uint:
|
||||
fprintf(f, "%" PRIu64, p->intval);
|
||||
break;
|
||||
|
||||
case nt_uint128:
|
||||
{
|
||||
char buf[64];
|
||||
fputs(uint128_hilo_to_str(buf, p->intval_hi, p->intval), f);
|
||||
}
|
||||
break;
|
||||
|
||||
case nt_string:
|
||||
print_quoted_string(f, p->strval.c_str());
|
||||
break;
|
||||
|
||||
default:
|
||||
jassert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void json::print_yaml(FILE *f, bool pretty, bool sorted, const node *p, int level_o,
|
||||
int level_a, bool cont)
|
||||
{
|
||||
bool is_obj = (p->type == nt_object);
|
||||
switch (p->type)
|
||||
{
|
||||
case nt_object:
|
||||
case nt_array:
|
||||
if (!p->childs.empty())
|
||||
{
|
||||
if (!cont)
|
||||
fputs("\n", f);
|
||||
for (node::const_iterator it(p, sorted); !it.at_end(); ++it)
|
||||
{
|
||||
int spaces = (cont ? 1 : (is_obj ? level_o : level_a) * 2);
|
||||
if (spaces > 0)
|
||||
fprintf(f, "%*s", spaces, "");
|
||||
const node *p2 = *it;
|
||||
if (!p2)
|
||||
{
|
||||
// Unset element of sparse array
|
||||
jassert(!is_obj);
|
||||
fputs("-" /*" null"*/ "\n", f);
|
||||
}
|
||||
else
|
||||
{
|
||||
jassert(is_obj == !p2->key.empty());
|
||||
if (is_obj)
|
||||
fprintf(f, "%s:", p2->key.c_str());
|
||||
else
|
||||
putc('-', f);
|
||||
// Recurse
|
||||
print_yaml(f, pretty, sorted, p2, (is_obj ? level_o : level_a) + 1,
|
||||
(is_obj ? level_o + (pretty ? 1 : 0) : level_a + 1), !is_obj);
|
||||
}
|
||||
cont = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fputs((is_obj ? "{}\n" : "[]\n"), f);
|
||||
}
|
||||
break;
|
||||
|
||||
case nt_bool:
|
||||
fputs((p->intval ? " true\n" : " false\n"), f);
|
||||
break;
|
||||
|
||||
case nt_int:
|
||||
fprintf(f, " %" PRId64 "\n", (int64_t)p->intval);
|
||||
break;
|
||||
|
||||
case nt_uint:
|
||||
fprintf(f, " %" PRIu64 "\n", p->intval);
|
||||
break;
|
||||
|
||||
case nt_uint128:
|
||||
{
|
||||
char buf[64];
|
||||
fprintf(f, " %s\n", uint128_hilo_to_str(buf, p->intval_hi, p->intval));
|
||||
}
|
||||
break;
|
||||
|
||||
case nt_string:
|
||||
putc(' ', f);
|
||||
switch (yaml_string_needs_quotes(p->strval.c_str()))
|
||||
{
|
||||
default:
|
||||
print_quoted_string(f, p->strval.c_str());
|
||||
break;
|
||||
case '\'':
|
||||
fprintf(f, "'%s'", p->strval.c_str());
|
||||
break;
|
||||
case 0:
|
||||
fputs(p->strval.c_str(), f);
|
||||
break;
|
||||
}
|
||||
putc('\n', f);
|
||||
break;
|
||||
|
||||
default:
|
||||
jassert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void json::print_flat(FILE *f, const char *assign, bool sorted, const node *p,
|
||||
std::string &path)
|
||||
{
|
||||
bool is_obj = (p->type == nt_object);
|
||||
switch (p->type)
|
||||
{
|
||||
case nt_object:
|
||||
case nt_array:
|
||||
fprintf(f, "%s%s%s;\n", path.c_str(), assign, (is_obj ? "{}" : "[]"));
|
||||
if (!p->childs.empty())
|
||||
{
|
||||
unsigned len = path.size();
|
||||
for (node::const_iterator it(p, sorted); !it.at_end(); ++it)
|
||||
{
|
||||
const node *p2 = *it;
|
||||
if (!is_obj)
|
||||
{
|
||||
char buf[10];
|
||||
snprintf(buf, sizeof(buf), "[%u]", it.array_index());
|
||||
path += buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
path += '.';
|
||||
path += p2->key;
|
||||
}
|
||||
if (!p2)
|
||||
{
|
||||
// Unset element of sparse array
|
||||
jassert(!is_obj);
|
||||
fprintf(f, "%s%snull;\n", path.c_str(), assign);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Recurse
|
||||
print_flat(f, assign, sorted, p2, path);
|
||||
}
|
||||
path.erase(len);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case nt_bool:
|
||||
fprintf(f, "%s%s%s;\n", path.c_str(), assign, (p->intval ? "true" : "false"));
|
||||
break;
|
||||
|
||||
case nt_int:
|
||||
fprintf(f, "%s%s%" PRId64 ";\n", path.c_str(), assign, (int64_t)p->intval);
|
||||
break;
|
||||
|
||||
case nt_uint:
|
||||
fprintf(f, "%s%s%" PRIu64 ";\n", path.c_str(), assign, p->intval);
|
||||
break;
|
||||
|
||||
case nt_uint128:
|
||||
{
|
||||
char buf[64];
|
||||
fprintf(f, "%s%s%s;\n", path.c_str(), assign,
|
||||
uint128_hilo_to_str(buf, p->intval_hi, p->intval));
|
||||
}
|
||||
break;
|
||||
|
||||
case nt_string:
|
||||
fprintf(f, "%s%s", path.c_str(), assign);
|
||||
print_quoted_string(f, p->strval.c_str());
|
||||
fputs(";\n", f);
|
||||
break;
|
||||
|
||||
default:
|
||||
jassert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void json::print(FILE *f, const print_options &options) const
|
||||
{
|
||||
if (m_root_node.type == nt_unset)
|
||||
return;
|
||||
jassert(m_root_node.type == nt_object);
|
||||
|
||||
switch (options.format)
|
||||
{
|
||||
default:
|
||||
print_json(f, options.pretty, options.sorted, &m_root_node, 0);
|
||||
if (options.pretty)
|
||||
putc('\n', f);
|
||||
break;
|
||||
case 'y':
|
||||
fputs("---", f);
|
||||
print_yaml(f, options.pretty, options.sorted, &m_root_node, 0, 0, false);
|
||||
break;
|
||||
case 'g':
|
||||
{
|
||||
std::string path("json");
|
||||
print_flat(f, (options.pretty ? " = " : "="), options.sorted, &m_root_node, path);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -1,305 +0,0 @@
|
|||
/*
|
||||
* json.h
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2017-22 Christian Franke
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef JSON_H_CVSID
|
||||
#define JSON_H_CVSID "$Id: json.h 5292 2022-01-06 17:13:25Z chrfranke $"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/// Create and print JSON output.
|
||||
class json
|
||||
{
|
||||
public:
|
||||
/// Return true if value is a safe JSON integer.
|
||||
/// Same as Number.isSafeInteger(value) in JavaScript.
|
||||
static bool is_safe_uint(unsigned long long value)
|
||||
{
|
||||
return (value < (1ULL << 53));
|
||||
}
|
||||
|
||||
/// Replace space and non-alphanumerics with '_', upper to lower case.
|
||||
static std::string str2key(const char *str);
|
||||
|
||||
/// Replace space and non-alphanumerics with '_', upper to lower case
|
||||
/// (std::string variant).
|
||||
static std::string str2key(const std::string &str)
|
||||
{
|
||||
return str2key(str.c_str());
|
||||
}
|
||||
|
||||
enum node_type
|
||||
{
|
||||
nt_unset,
|
||||
nt_object,
|
||||
nt_array,
|
||||
nt_bool,
|
||||
nt_int,
|
||||
nt_uint,
|
||||
nt_uint128,
|
||||
nt_string
|
||||
};
|
||||
|
||||
// initializer_list<> elements.
|
||||
struct initlist_value
|
||||
{
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
initlist_value(node_type t) : type(t) {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
initlist_value(bool v) : type(nt_bool), intval(v ? 1 : 0) {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
initlist_value(int v) : initlist_value((long long)v) {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
initlist_value(unsigned v) : initlist_value((unsigned long long)v) {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
initlist_value(long v) : initlist_value((long long)v) {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
initlist_value(unsigned long v) : initlist_value((unsigned long long)v) {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
initlist_value(long long v) : type(nt_int), intval((uint64_t)(int64_t)v) {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
initlist_value(unsigned long long v) : type(nt_uint), intval((uint64_t)v) {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
initlist_value(const char *v) : type(nt_string), strval(v) {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
initlist_value(const std::string &v) : type(nt_string), strval(v.c_str()) {}
|
||||
node_type type;
|
||||
uint64_t intval = 0;
|
||||
const char *strval = nullptr;
|
||||
};
|
||||
|
||||
struct initlist_key_value_pair
|
||||
{
|
||||
initlist_key_value_pair(const char *k, const initlist_value &v) : keystr(k), value(v) {}
|
||||
initlist_key_value_pair(const std::string &k, const initlist_value &v)
|
||||
: keystr(k.c_str()), value(v) {}
|
||||
initlist_key_value_pair(const char *k, const std::initializer_list<initlist_key_value_pair> &ilist)
|
||||
: keystr(k), value(nt_object), object(ilist) {}
|
||||
initlist_key_value_pair(const std::string &k, const std::initializer_list<initlist_key_value_pair> &ilist)
|
||||
: keystr(k.c_str()), value(nt_object), object(ilist) {}
|
||||
initlist_key_value_pair(const char *k, const std::initializer_list<initlist_value> &ilist)
|
||||
: keystr(k), value(nt_array), array(ilist) {}
|
||||
initlist_key_value_pair(const std::string &k, const std::initializer_list<initlist_value> &ilist)
|
||||
: keystr(k.c_str()), value(nt_array), array(ilist) {}
|
||||
const char *keystr;
|
||||
initlist_value value;
|
||||
std::initializer_list<initlist_key_value_pair> object;
|
||||
std::initializer_list<initlist_value> array;
|
||||
};
|
||||
|
||||
private:
|
||||
struct node_info
|
||||
{
|
||||
std::string key;
|
||||
int index = 0;
|
||||
|
||||
node_info() = default;
|
||||
explicit node_info(const char *keystr) : key(str2key(keystr)) {}
|
||||
explicit node_info(int index_) : index(index_) {}
|
||||
};
|
||||
|
||||
typedef std::vector<node_info> node_path;
|
||||
|
||||
public:
|
||||
/// Reference to a JSON element.
|
||||
class ref
|
||||
{
|
||||
public:
|
||||
~ref();
|
||||
|
||||
/// Return reference to object element.
|
||||
ref operator[](const char *keystr) const
|
||||
{
|
||||
return ref(*this, keystr);
|
||||
}
|
||||
|
||||
/// Return reference to object element (std::string variant).
|
||||
ref operator[](const std::string &keystr) const
|
||||
{
|
||||
return ref(*this, keystr.c_str());
|
||||
}
|
||||
|
||||
/// Return reference to array element.
|
||||
ref operator[](int index) const
|
||||
{
|
||||
return ref(*this, index);
|
||||
}
|
||||
|
||||
// Assignment operators create or change element.
|
||||
void operator=(bool value);
|
||||
|
||||
void operator=(int value);
|
||||
void operator=(unsigned value);
|
||||
void operator=(long value);
|
||||
void operator=(unsigned long value);
|
||||
void operator=(long long value);
|
||||
void operator=(unsigned long long value);
|
||||
|
||||
void operator=(const char *value);
|
||||
void operator=(const std::string &value);
|
||||
|
||||
/// Return reference to element with KEY_SUFFIX appended to last key.
|
||||
ref with_suffix(const char *key_suffix) const
|
||||
{
|
||||
return ref(*this, "", key_suffix);
|
||||
}
|
||||
|
||||
void set_uint128(uint64_t value_hi, uint64_t value_lo);
|
||||
|
||||
// Output only if safe integer.
|
||||
bool set_if_safe_uint64(uint64_t value);
|
||||
bool set_if_safe_uint128(uint64_t value_hi, uint64_t value_lo);
|
||||
bool set_if_safe_le128(const void *pvalue);
|
||||
|
||||
// If unsafe integer, output also as string with key "NUMBER_s".
|
||||
void set_unsafe_uint64(uint64_t value);
|
||||
void set_unsafe_uint128(uint64_t value_hi, uint64_t value_lo);
|
||||
void set_unsafe_le128(const void *pvalue);
|
||||
|
||||
/// Braced-init-list support for nested objects.
|
||||
void operator+=(std::initializer_list<initlist_key_value_pair> ilist);
|
||||
/// Braced-init-list support for simple arrays.
|
||||
void operator+=(std::initializer_list<initlist_value> ilist);
|
||||
|
||||
private:
|
||||
friend class json;
|
||||
explicit ref(json &js);
|
||||
ref(json &js, const char *keystr);
|
||||
ref(const ref &base, const char *keystr);
|
||||
ref(const ref &base, int index);
|
||||
ref(const ref &base, const char * /*dummy*/, const char *key_suffix);
|
||||
|
||||
void operator=(const initlist_value &value)
|
||||
{
|
||||
m_js.set_initlist_value(m_path, value);
|
||||
}
|
||||
|
||||
json &m_js;
|
||||
node_path m_path;
|
||||
};
|
||||
|
||||
/// Return reference to element of top level object.
|
||||
ref operator[](const char *keystr)
|
||||
{
|
||||
return ref(*this, keystr);
|
||||
}
|
||||
|
||||
/// Return reference to element of top level object (std::string variant).
|
||||
ref operator[](const std::string &keystr)
|
||||
{
|
||||
return ref(*this, keystr.c_str());
|
||||
}
|
||||
|
||||
/// Braced-init-list support for top level object.
|
||||
void operator+=(std::initializer_list<initlist_key_value_pair> ilist)
|
||||
{
|
||||
ref(*this) += ilist;
|
||||
}
|
||||
|
||||
/// Enable/disable JSON output.
|
||||
void enable(bool yes = true)
|
||||
{
|
||||
m_enabled = yes;
|
||||
}
|
||||
|
||||
/// Return true if enabled.
|
||||
bool is_enabled() const
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
/// Enable/disable extra string output for safe integers also.
|
||||
void set_verbose(bool yes = true)
|
||||
{
|
||||
m_verbose = yes;
|
||||
}
|
||||
|
||||
/// Return true if any 128-bit value has been output.
|
||||
bool has_uint128_output() const
|
||||
{
|
||||
return m_uint128_output;
|
||||
}
|
||||
|
||||
/// Options for print().
|
||||
struct print_options
|
||||
{
|
||||
bool pretty = false; //< Pretty-print output.
|
||||
bool sorted = false; //< Sort object keys.
|
||||
char format = 0; //< 'y': YAML, 'g': flat(grep, gron), other: JSON
|
||||
};
|
||||
|
||||
/// Print JSON tree to a file.
|
||||
void print(FILE *f, const print_options &options) const;
|
||||
|
||||
private:
|
||||
struct node
|
||||
{
|
||||
node();
|
||||
node(const node &) = delete;
|
||||
explicit node(const std::string &key_);
|
||||
~node();
|
||||
void operator=(const node &) = delete;
|
||||
|
||||
node_type type = nt_unset;
|
||||
|
||||
uint64_t intval = 0, intval_hi = 0;
|
||||
std::string strval;
|
||||
|
||||
std::string key;
|
||||
std::vector<std::unique_ptr<node>> childs;
|
||||
typedef std::map<std::string, unsigned> keymap;
|
||||
keymap key2index;
|
||||
|
||||
class const_iterator
|
||||
{
|
||||
public:
|
||||
const_iterator(const node *node_p, bool sorted);
|
||||
bool at_end() const;
|
||||
unsigned array_index() const;
|
||||
void operator++();
|
||||
const node *operator*() const;
|
||||
|
||||
private:
|
||||
const node *m_node_p;
|
||||
bool m_use_map;
|
||||
unsigned m_child_idx = 0;
|
||||
keymap::const_iterator m_key_iter;
|
||||
};
|
||||
};
|
||||
|
||||
bool m_enabled = false;
|
||||
bool m_verbose = false;
|
||||
bool m_uint128_output = false;
|
||||
|
||||
node m_root_node;
|
||||
|
||||
node *find_or_create_node(const node_path &path, node_type type);
|
||||
|
||||
void set_bool(const node_path &path, bool value);
|
||||
void set_int64(const node_path &path, int64_t value);
|
||||
void set_uint64(const node_path &path, uint64_t value);
|
||||
void set_uint128(const node_path &path, uint64_t value_hi, uint64_t value_lo);
|
||||
void set_cstring(const node_path &path, const char *value);
|
||||
void set_string(const node_path &path, const std::string &value);
|
||||
void set_initlist_value(const node_path &path, const initlist_value &value);
|
||||
|
||||
static void print_json(FILE *f, bool pretty, bool sorted, const node *p, int level);
|
||||
static void print_yaml(FILE *f, bool pretty, bool sorted, const node *p, int level_o,
|
||||
int level_a, bool cont);
|
||||
static void print_flat(FILE *f, const char *assign, bool sorted, const node *p,
|
||||
std::string &path);
|
||||
};
|
||||
|
||||
#endif // JSON_H_CVSID
|
File diff suppressed because it is too large
Load Diff
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
* knowndrives.h
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2003-11 Philip Williams, Bruce Allen
|
||||
* Copyright (C) 2008-21 Christian Franke
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KNOWNDRIVES_H_
|
||||
#define KNOWNDRIVES_H_
|
||||
|
||||
#define KNOWNDRIVES_H_CVSID "$Id: knowndrives.h 5207 2021-02-09 20:25:13Z chrfranke $\n"
|
||||
|
||||
// Structure to store drive database entries, see drivedb.h for a description.
|
||||
struct drive_settings
|
||||
{
|
||||
const char *modelfamily;
|
||||
const char *modelregexp;
|
||||
const char *firmwareregexp;
|
||||
const char *warningmsg;
|
||||
const char *presets;
|
||||
};
|
||||
|
||||
// info returned by lookup_usb_device()
|
||||
struct usb_dev_info
|
||||
{
|
||||
std::string usb_device; // Device name, empty if unknown
|
||||
std::string usb_bridge; // USB bridge name, empty if unknown
|
||||
std::string usb_type; // Type string ('-d' option).
|
||||
};
|
||||
|
||||
// Search drivedb for USB device with vendor:product ID.
|
||||
int lookup_usb_device(int vendor_id, int product_id, int bcd_device,
|
||||
usb_dev_info &info, usb_dev_info &info2);
|
||||
|
||||
// Shows the presets (if any) that are available for the given drive.
|
||||
void show_presets(const ata_identify_device *drive);
|
||||
|
||||
// Shows all presets for drives in knowndrives[].
|
||||
// Returns #syntax errors.
|
||||
int showallpresets();
|
||||
|
||||
// Shows all matching presets for a drive in knowndrives[].
|
||||
// Returns # matching entries.
|
||||
int showmatchingpresets(const char *model, const char *firmware);
|
||||
|
||||
// Searches drive database and sets preset vendor attribute
|
||||
// options in defs and firmwarebugs.
|
||||
// Values that have already been set will not be changed.
|
||||
// Returns pointer to database entry or nullptr if none found.
|
||||
const drive_settings *lookup_drive_apply_presets(
|
||||
const ata_identify_device *drive, ata_vendor_attr_defs &defs,
|
||||
firmwarebug_defs &firmwarebugs, std::string &dbversion);
|
||||
|
||||
// Get path for additional database file
|
||||
const char *get_drivedb_path_add();
|
||||
|
||||
#ifdef SMARTMONTOOLS_DRIVEDBDIR
|
||||
// Get path for default database file
|
||||
const char *get_drivedb_path_default();
|
||||
#endif
|
||||
|
||||
// Read drive database from file.
|
||||
bool read_drive_database(const char *path);
|
||||
|
||||
// Init default db entry and optionally read drive databases from standard places.
|
||||
bool init_drive_database(bool use_default_db);
|
||||
|
||||
// Get vendor attribute options from default db entry.
|
||||
const ata_vendor_attr_defs &get_default_attr_defs();
|
||||
|
||||
#endif
|
|
@ -1,60 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
/*
|
||||
* Definitions for the NVM Express ioctl interface
|
||||
* Copyright (c) 2011-2014, Intel Corporation.
|
||||
*/
|
||||
|
||||
#ifndef _UAPI_LINUX_NVME_IOCTL_H
|
||||
#define _UAPI_LINUX_NVME_IOCTL_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct nvme_user_io
|
||||
{
|
||||
__u8 opcode;
|
||||
__u8 flags;
|
||||
__u16 control;
|
||||
__u16 nblocks;
|
||||
__u16 rsvd;
|
||||
__u64 metadata;
|
||||
__u64 addr;
|
||||
__u64 slba;
|
||||
__u32 dsmgmt;
|
||||
__u32 reftag;
|
||||
__u16 apptag;
|
||||
__u16 appmask;
|
||||
};
|
||||
|
||||
struct nvme_passthru_cmd
|
||||
{
|
||||
__u8 opcode;
|
||||
__u8 flags;
|
||||
__u16 rsvd1;
|
||||
__u32 nsid;
|
||||
__u32 cdw2;
|
||||
__u32 cdw3;
|
||||
__u64 metadata;
|
||||
__u64 addr;
|
||||
__u32 metadata_len;
|
||||
__u32 data_len;
|
||||
__u32 cdw10;
|
||||
__u32 cdw11;
|
||||
__u32 cdw12;
|
||||
__u32 cdw13;
|
||||
__u32 cdw14;
|
||||
__u32 cdw15;
|
||||
__u32 timeout_ms;
|
||||
__u32 result;
|
||||
};
|
||||
|
||||
#define nvme_admin_cmd nvme_passthru_cmd
|
||||
|
||||
#define NVME_IOCTL_ID _IO('N', 0x40)
|
||||
#define NVME_IOCTL_ADMIN_CMD _IOWR('N', 0x41, struct nvme_admin_cmd)
|
||||
#define NVME_IOCTL_SUBMIT_IO _IOW('N', 0x42, struct nvme_user_io)
|
||||
#define NVME_IOCTL_IO_CMD _IOWR('N', 0x43, struct nvme_passthru_cmd)
|
||||
#define NVME_IOCTL_RESET _IO('N', 0x44)
|
||||
#define NVME_IOCTL_SUBSYS_RESET _IO('N', 0x45)
|
||||
#define NVME_IOCTL_RESCAN _IO('N', 0x46)
|
||||
|
||||
#endif /* _UAPI_LINUX_NVME_IOCTL_H */
|
|
@ -1,282 +0,0 @@
|
|||
/*
|
||||
* megaraid.h
|
||||
*
|
||||
* Home page of code is: http://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2008 Jordan Hargrave
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
int megaraid_io_interface(int device, int target, struct scsi_cmnd_io *, int);
|
||||
|
||||
#undef u32
|
||||
|
||||
#define u8 uint8_t
|
||||
#define u16 uint16_t
|
||||
#define u32 uint32_t
|
||||
#define u64 uint64_t
|
||||
|
||||
/*======================================================
|
||||
* PERC2/3/4 Passthrough SCSI Command Interface
|
||||
*
|
||||
* Contents from:
|
||||
* drivers/scsi/megaraid/megaraid_ioctl.h
|
||||
* drivers/scsi/megaraid/mbox_defs.h
|
||||
*======================================================*/
|
||||
#define MEGAIOC_MAGIC 'm'
|
||||
#define MEGAIOCCMD _IOWR(MEGAIOC_MAGIC, 0, struct uioctl_t)
|
||||
|
||||
/* Following subopcode work for opcode == 0x82 */
|
||||
#define MKADAP(adapno) (MEGAIOC_MAGIC << 8 | adapno)
|
||||
#define MEGAIOC_QNADAP 'm'
|
||||
#define MEGAIOC_QDRVRVER 'e'
|
||||
#define MEGAIOC_QADAPINFO 'g'
|
||||
|
||||
#define MEGA_MBOXCMD_PASSTHRU 0x03
|
||||
|
||||
#define MAX_REQ_SENSE_LEN 0x20
|
||||
#define MAX_CDB_LEN 10
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t timeout : 3;
|
||||
uint8_t ars : 1;
|
||||
uint8_t reserved : 3;
|
||||
uint8_t islogical : 1;
|
||||
uint8_t logdrv;
|
||||
uint8_t channel;
|
||||
uint8_t target;
|
||||
uint8_t queuetag;
|
||||
uint8_t queueaction;
|
||||
uint8_t cdb[MAX_CDB_LEN];
|
||||
uint8_t cdblen;
|
||||
uint8_t reqsenselen;
|
||||
uint8_t reqsensearea[MAX_REQ_SENSE_LEN];
|
||||
uint8_t numsgelements;
|
||||
uint8_t scsistatus;
|
||||
uint32_t dataxferaddr;
|
||||
uint32_t dataxferlen;
|
||||
} __attribute__((packed)) mega_passthru;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t cmd;
|
||||
uint8_t cmdid;
|
||||
uint8_t opcode;
|
||||
uint8_t subopcode;
|
||||
uint32_t lba;
|
||||
uint32_t xferaddr;
|
||||
uint8_t logdrv;
|
||||
uint8_t resvd[3];
|
||||
uint8_t numstatus;
|
||||
uint8_t status;
|
||||
} __attribute__((packed)) megacmd_t;
|
||||
|
||||
typedef union
|
||||
{
|
||||
uint8_t *pointer;
|
||||
uint8_t pad[8];
|
||||
} ptr_t;
|
||||
|
||||
// The above definition assumes sizeof(void*) <= 8.
|
||||
// This assumption also exists in the linux megaraid device driver.
|
||||
// So define a macro to check expected size of ptr_t at compile time using
|
||||
// a dummy typedef. On size mismatch, compiler reports a negative array
|
||||
// size. If you see an error message of this form, it means that
|
||||
// you have an unexpected pointer size on your platform and can not
|
||||
// use megaraid support in smartmontools.
|
||||
typedef char assert_sizeof_ptr_t[sizeof(ptr_t) == 8 ? 1 : -1];
|
||||
|
||||
struct uioctl_t
|
||||
{
|
||||
uint32_t inlen;
|
||||
uint32_t outlen;
|
||||
union
|
||||
{
|
||||
uint8_t fca[16];
|
||||
struct
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t subopcode;
|
||||
uint16_t adapno;
|
||||
ptr_t buffer;
|
||||
uint32_t length;
|
||||
} __attribute__((packed)) fcs;
|
||||
} __attribute__((packed)) ui;
|
||||
|
||||
megacmd_t mbox;
|
||||
mega_passthru pthru;
|
||||
ptr_t data;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*===================================================
|
||||
* PERC5/6 Passthrough SCSI Command Interface
|
||||
*
|
||||
* Contents from:
|
||||
* drivers/scsi/megaraid/megaraid_sas.h
|
||||
*===================================================*/
|
||||
#define MEGASAS_MAGIC 'M'
|
||||
#define MEGASAS_IOC_FIRMWARE _IOWR(MEGASAS_MAGIC, 1, struct megasas_iocpacket)
|
||||
|
||||
#define MFI_CMD_PD_SCSI_IO 0x04
|
||||
#define MFI_CMD_DCMD 0x05
|
||||
#define MFI_FRAME_SGL64 0x02
|
||||
#define MFI_STAT_OK 0x00
|
||||
#define MFI_DCMD_PD_GET_LIST 0x02010000
|
||||
/*
|
||||
* Number of mailbox bytes in DCMD message frame
|
||||
*/
|
||||
#define MFI_MBOX_SIZE 12
|
||||
#define MAX_IOCTL_SGE 16
|
||||
#define MFI_FRAME_DIR_NONE 0x0000
|
||||
#define MFI_FRAME_DIR_WRITE 0x0008
|
||||
#define MFI_FRAME_DIR_READ 0x0010
|
||||
#define MFI_FRAME_DIR_BOTH 0x0018
|
||||
|
||||
#define MAX_SYS_PDS 240
|
||||
|
||||
struct megasas_sge32
|
||||
{
|
||||
|
||||
u32 phys_addr;
|
||||
u32 length;
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
struct megasas_sge64
|
||||
{
|
||||
|
||||
u64 phys_addr;
|
||||
u32 length;
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
union megasas_sgl
|
||||
{
|
||||
|
||||
struct megasas_sge32 sge32[1];
|
||||
struct megasas_sge64 sge64[1];
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
struct megasas_header
|
||||
{
|
||||
|
||||
u8 cmd; /*00h */
|
||||
u8 sense_len; /*01h */
|
||||
u8 cmd_status; /*02h */
|
||||
u8 scsi_status; /*03h */
|
||||
|
||||
u8 target_id; /*04h */
|
||||
u8 lun; /*05h */
|
||||
u8 cdb_len; /*06h */
|
||||
u8 sge_count; /*07h */
|
||||
|
||||
u32 context; /*08h */
|
||||
u32 pad_0; /*0Ch */
|
||||
|
||||
u16 flags; /*10h */
|
||||
u16 timeout; /*12h */
|
||||
u32 data_xferlen; /*14h */
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
struct megasas_pthru_frame
|
||||
{
|
||||
|
||||
u8 cmd; /*00h */
|
||||
u8 sense_len; /*01h */
|
||||
u8 cmd_status; /*02h */
|
||||
u8 scsi_status; /*03h */
|
||||
|
||||
u8 target_id; /*04h */
|
||||
u8 lun; /*05h */
|
||||
u8 cdb_len; /*06h */
|
||||
u8 sge_count; /*07h */
|
||||
|
||||
u32 context; /*08h */
|
||||
u32 pad_0; /*0Ch */
|
||||
|
||||
u16 flags; /*10h */
|
||||
u16 timeout; /*12h */
|
||||
u32 data_xfer_len; /*14h */
|
||||
|
||||
u32 sense_buf_phys_addr_lo; /*18h */
|
||||
u32 sense_buf_phys_addr_hi; /*1Ch */
|
||||
|
||||
u8 cdb[16]; /*20h */
|
||||
union megasas_sgl sgl; /*30h */
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
struct megasas_dcmd_frame
|
||||
{
|
||||
|
||||
u8 cmd; /*00h */
|
||||
u8 reserved_0; /*01h */
|
||||
u8 cmd_status; /*02h */
|
||||
u8 reserved_1[4]; /*03h */
|
||||
u8 sge_count; /*07h */
|
||||
|
||||
u32 context; /*08h */
|
||||
u32 pad_0; /*0Ch */
|
||||
|
||||
u16 flags; /*10h */
|
||||
u16 timeout; /*12h */
|
||||
|
||||
u32 data_xfer_len; /*14h */
|
||||
u32 opcode; /*18h */
|
||||
|
||||
union
|
||||
{ /*1Ch */
|
||||
u8 b[12];
|
||||
u16 s[6];
|
||||
u32 w[3];
|
||||
} mbox;
|
||||
|
||||
union megasas_sgl sgl; /*28h */
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
struct megasas_iocpacket
|
||||
{
|
||||
u16 host_no;
|
||||
u16 __pad1;
|
||||
u32 sgl_off;
|
||||
u32 sge_count;
|
||||
u32 sense_off;
|
||||
u32 sense_len;
|
||||
union
|
||||
{
|
||||
u8 raw[128];
|
||||
struct megasas_header hdr;
|
||||
struct megasas_pthru_frame pthru;
|
||||
struct megasas_dcmd_frame dcmd;
|
||||
} frame;
|
||||
|
||||
struct iovec sgl[MAX_IOCTL_SGE];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct megasas_pd_address
|
||||
{
|
||||
u16 device_id;
|
||||
u16 encl_device_id;
|
||||
u8 encl_index;
|
||||
u8 slot_number;
|
||||
u8 scsi_dev_type; /* 0 = disk */
|
||||
u8 connect_port_bitmap;
|
||||
u64 sas_addr[2];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct megasas_pd_list
|
||||
{
|
||||
u32 size;
|
||||
u32 count;
|
||||
struct megasas_pd_address addr[MAX_SYS_PDS];
|
||||
} __attribute__((packed));
|
||||
|
||||
#undef u8
|
||||
#undef u16
|
||||
#undef u32
|
||||
#undef u64
|
|
@ -1,274 +0,0 @@
|
|||
/*
|
||||
* nvmecmds.cpp
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2016-21 Christian Franke
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "nvmecmds.h"
|
||||
|
||||
const char *nvmecmds_cvsid = "$Id: nvmecmds.cpp 5219 2021-06-04 16:39:50Z chrfranke $" NVMECMDS_H_CVSID;
|
||||
|
||||
#include "dev_interface.h"
|
||||
#include "atacmds.h" // swapx(), dont_print_serial_number
|
||||
#include "scsicmds.h" // dStrHex()
|
||||
#include "utility.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
using namespace smartmontools;
|
||||
|
||||
// Print NVMe debug messages?
|
||||
unsigned char nvme_debugmode = 0;
|
||||
|
||||
// Dump up to 4096 bytes, do not dump trailing zero bytes.
|
||||
// TODO: Handle this by new unified function in utility.cpp
|
||||
static void debug_hex_dump(const void *data, unsigned size)
|
||||
{
|
||||
const unsigned char *p = (const unsigned char *)data;
|
||||
const unsigned limit = 4096; // sizeof(nvme_id_ctrl)
|
||||
unsigned sz = (size <= limit ? size : limit);
|
||||
|
||||
while (sz > 0x10 && !p[sz - 1])
|
||||
sz--;
|
||||
if (sz < size)
|
||||
{
|
||||
if (sz & 0x0f)
|
||||
sz = (sz & ~0x0f) + 0x10;
|
||||
sz += 0x10;
|
||||
if (sz > size)
|
||||
sz = size;
|
||||
}
|
||||
|
||||
dStrHex((const uint8_t *)p, sz, 0);
|
||||
if (sz < size)
|
||||
pout(" ...\n");
|
||||
}
|
||||
|
||||
// Call NVMe pass-through and print debug info if requested.
|
||||
static bool nvme_pass_through(nvme_device *device, const nvme_cmd_in &in,
|
||||
nvme_cmd_out &out)
|
||||
{
|
||||
if (nvme_debugmode)
|
||||
{
|
||||
pout(" [NVMe call: opcode=0x%02x, size=0x%04x, nsid=0x%08x, cdw10=0x%08x",
|
||||
in.opcode, in.size, in.nsid, in.cdw10);
|
||||
if (in.cdw11 || in.cdw12 || in.cdw13 || in.cdw14 || in.cdw15)
|
||||
pout(",\n cdw1x=0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x",
|
||||
in.cdw11, in.cdw12, in.cdw13, in.cdw14, in.cdw15);
|
||||
pout("]\n");
|
||||
}
|
||||
|
||||
auto start_usec = (nvme_debugmode ? get_timer_usec() : -1);
|
||||
|
||||
bool ok = device->nvme_pass_through(in, out);
|
||||
|
||||
if (start_usec >= 0)
|
||||
{
|
||||
auto duration_usec = get_timer_usec() - start_usec;
|
||||
if (duration_usec > 0)
|
||||
pout(" [Duration: %.6fs]\n", duration_usec / 1000000.0);
|
||||
}
|
||||
|
||||
if (dont_print_serial_number && ok && in.opcode == nvme_admin_identify && in.cdw10 == 0x01)
|
||||
{
|
||||
// Invalidate serial number
|
||||
nvme_id_ctrl &id_ctrl = *reinterpret_cast<nvme_id_ctrl *>(in.buffer);
|
||||
memset(id_ctrl.sn, 'X', sizeof(id_ctrl.sn));
|
||||
}
|
||||
|
||||
if (nvme_debugmode)
|
||||
{
|
||||
if (!ok)
|
||||
{
|
||||
pout(" [NVMe call failed: ");
|
||||
if (out.status_valid)
|
||||
pout("NVMe Status=0x%04x", out.status);
|
||||
else
|
||||
pout("%s", device->get_errmsg());
|
||||
}
|
||||
else
|
||||
{
|
||||
pout(" [NVMe call succeeded: result=0x%08x", out.result);
|
||||
if (nvme_debugmode > 1 && in.direction() == nvme_cmd_in::data_in)
|
||||
{
|
||||
pout("\n");
|
||||
debug_hex_dump(in.buffer, in.size);
|
||||
pout(" ");
|
||||
}
|
||||
}
|
||||
pout("]\n");
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
// Call NVMe pass-through and print debug info if requested.
|
||||
// Version without output parameters.
|
||||
static bool nvme_pass_through(nvme_device *device, const nvme_cmd_in &in)
|
||||
{
|
||||
nvme_cmd_out out;
|
||||
return nvme_pass_through(device, in, out);
|
||||
}
|
||||
|
||||
// Read NVMe identify info with controller/namespace field CNS.
|
||||
static bool nvme_read_identify(nvme_device *device, unsigned nsid,
|
||||
unsigned char cns, void *data, unsigned size)
|
||||
{
|
||||
memset(data, 0, size);
|
||||
nvme_cmd_in in;
|
||||
in.set_data_in(nvme_admin_identify, data, size);
|
||||
in.nsid = nsid;
|
||||
in.cdw10 = cns;
|
||||
|
||||
return nvme_pass_through(device, in);
|
||||
}
|
||||
|
||||
// Read NVMe Identify Controller data structure.
|
||||
bool nvme_read_id_ctrl(nvme_device *device, nvme_id_ctrl &id_ctrl)
|
||||
{
|
||||
if (!nvme_read_identify(device, 0, 0x01, &id_ctrl, sizeof(id_ctrl)))
|
||||
return false;
|
||||
|
||||
if (isbigendian())
|
||||
{
|
||||
swapx(&id_ctrl.vid);
|
||||
swapx(&id_ctrl.ssvid);
|
||||
swapx(&id_ctrl.cntlid);
|
||||
swapx(&id_ctrl.ver);
|
||||
swapx(&id_ctrl.oacs);
|
||||
swapx(&id_ctrl.wctemp);
|
||||
swapx(&id_ctrl.cctemp);
|
||||
swapx(&id_ctrl.mtfa);
|
||||
swapx(&id_ctrl.hmpre);
|
||||
swapx(&id_ctrl.hmmin);
|
||||
swapx(&id_ctrl.rpmbs);
|
||||
swapx(&id_ctrl.nn);
|
||||
swapx(&id_ctrl.oncs);
|
||||
swapx(&id_ctrl.fuses);
|
||||
swapx(&id_ctrl.awun);
|
||||
swapx(&id_ctrl.awupf);
|
||||
swapx(&id_ctrl.acwu);
|
||||
swapx(&id_ctrl.sgls);
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
swapx(&id_ctrl.psd[i].max_power);
|
||||
swapx(&id_ctrl.psd[i].entry_lat);
|
||||
swapx(&id_ctrl.psd[i].exit_lat);
|
||||
swapx(&id_ctrl.psd[i].idle_power);
|
||||
swapx(&id_ctrl.psd[i].active_power);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read NVMe Identify Namespace data structure for namespace NSID.
|
||||
bool nvme_read_id_ns(nvme_device *device, unsigned nsid, nvme_id_ns &id_ns)
|
||||
{
|
||||
if (!nvme_read_identify(device, nsid, 0x00, &id_ns, sizeof(id_ns)))
|
||||
return false;
|
||||
|
||||
if (isbigendian())
|
||||
{
|
||||
swapx(&id_ns.nsze);
|
||||
swapx(&id_ns.ncap);
|
||||
swapx(&id_ns.nuse);
|
||||
swapx(&id_ns.nawun);
|
||||
swapx(&id_ns.nawupf);
|
||||
swapx(&id_ns.nacwu);
|
||||
swapx(&id_ns.nabsn);
|
||||
swapx(&id_ns.nabo);
|
||||
swapx(&id_ns.nabspf);
|
||||
for (int i = 0; i < 16; i++)
|
||||
swapx(&id_ns.lbaf[i].ms);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool nvme_read_log_page_1(nvme_device *device, unsigned nsid,
|
||||
unsigned char lid, void *data, unsigned size, unsigned offset = 0)
|
||||
{
|
||||
if (!(4 <= size && size <= 0x1000 && !(size % 4) && !(offset % 4)))
|
||||
return device->set_err(EINVAL, "Invalid NVMe log size %u or offset %u", size, offset);
|
||||
|
||||
memset(data, 0, size);
|
||||
nvme_cmd_in in;
|
||||
in.set_data_in(nvme_admin_get_log_page, data, size);
|
||||
in.nsid = nsid;
|
||||
in.cdw10 = lid | (((size / 4) - 1) << 16);
|
||||
in.cdw12 = offset; // LPOL, NVMe 1.2.1
|
||||
|
||||
return nvme_pass_through(device, in);
|
||||
}
|
||||
|
||||
// Read NVMe log page with identifier LID.
|
||||
unsigned nvme_read_log_page(nvme_device *device, unsigned nsid, unsigned char lid,
|
||||
void *data, unsigned size, bool lpo_sup, unsigned offset /* = 0 */)
|
||||
{
|
||||
unsigned n, bs;
|
||||
for (n = 0; n < size; n += bs)
|
||||
{
|
||||
if (!lpo_sup && offset + n > 0)
|
||||
{
|
||||
device->set_err(ENOSYS, "Log Page Offset not supported");
|
||||
break;
|
||||
}
|
||||
|
||||
// Limit transfer size to one page to avoid problems with
|
||||
// limits of NVMe pass-through layer or too low MDTS values.
|
||||
bs = size - n;
|
||||
if (bs > 0x1000)
|
||||
bs = 0x1000;
|
||||
if (!nvme_read_log_page_1(device, nsid, lid, (char *)data + n, bs, offset + n))
|
||||
break;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
// Read NVMe Error Information Log.
|
||||
unsigned nvme_read_error_log(nvme_device *device, nvme_error_log_page *error_log,
|
||||
unsigned num_entries, bool lpo_sup)
|
||||
{
|
||||
unsigned n = nvme_read_log_page(device, 0xffffffff, 0x01, error_log,
|
||||
num_entries * sizeof(*error_log), lpo_sup);
|
||||
|
||||
if (isbigendian())
|
||||
{
|
||||
for (unsigned i = 0; i < n; i++)
|
||||
{
|
||||
swapx(&error_log[i].error_count);
|
||||
swapx(&error_log[i].sqid);
|
||||
swapx(&error_log[i].cmdid);
|
||||
swapx(&error_log[i].status_field);
|
||||
swapx(&error_log[i].parm_error_location);
|
||||
swapx(&error_log[i].lba);
|
||||
swapx(&error_log[i].nsid);
|
||||
}
|
||||
}
|
||||
|
||||
return n / sizeof(*error_log);
|
||||
}
|
||||
|
||||
// Read NVMe SMART/Health Information log.
|
||||
bool nvme_read_smart_log(nvme_device *device, nvme_smart_log &smart_log)
|
||||
{
|
||||
if (!nvme_read_log_page_1(device, 0xffffffff, 0x02, &smart_log, sizeof(smart_log)))
|
||||
return false;
|
||||
|
||||
if (isbigendian())
|
||||
{
|
||||
swapx(&smart_log.warning_temp_time);
|
||||
swapx(&smart_log.critical_comp_time);
|
||||
for (int i = 0; i < 8; i++)
|
||||
swapx(&smart_log.temp_sensor[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,249 +0,0 @@
|
|||
/*
|
||||
* nvmecmds.h
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2016-20 Christian Franke
|
||||
*
|
||||
* Original code from <linux/nvme.h>:
|
||||
* Copyright (C) 2011-2014 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef NVMECMDS_H
|
||||
#define NVMECMDS_H
|
||||
|
||||
#define NVMECMDS_H_CVSID "$Id: nvmecmds.h 5124 2020-12-04 20:40:43Z chrfranke $"
|
||||
|
||||
#include "static_assert.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// The code below was originally imported from <linux/nvme.h> include file from
|
||||
// Linux kernel sources. Types from <linux/types.h> were replaced.
|
||||
// Symbol names are unchanged but placed in a namespace to allow inclusion
|
||||
// of the original <linux/nvme.h>.
|
||||
namespace smartmontools {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// BEGIN: From <linux/nvme.h>
|
||||
|
||||
struct nvme_error_log_page {
|
||||
uint64_t error_count;
|
||||
unsigned short sqid;
|
||||
unsigned short cmdid;
|
||||
unsigned short status_field;
|
||||
unsigned short parm_error_location;
|
||||
uint64_t lba;
|
||||
unsigned int nsid;
|
||||
unsigned char vs;
|
||||
unsigned char resv[35];
|
||||
};
|
||||
STATIC_ASSERT(sizeof(nvme_error_log_page) == 64);
|
||||
|
||||
struct nvme_id_power_state {
|
||||
unsigned short max_power; // centiwatts
|
||||
unsigned char rsvd2;
|
||||
unsigned char flags;
|
||||
unsigned int entry_lat; // microseconds
|
||||
unsigned int exit_lat; // microseconds
|
||||
unsigned char read_tput;
|
||||
unsigned char read_lat;
|
||||
unsigned char write_tput;
|
||||
unsigned char write_lat;
|
||||
unsigned short idle_power;
|
||||
unsigned char idle_scale;
|
||||
unsigned char rsvd19;
|
||||
unsigned short active_power;
|
||||
unsigned char active_work_scale;
|
||||
unsigned char rsvd23[9];
|
||||
};
|
||||
STATIC_ASSERT(sizeof(nvme_id_power_state) == 32);
|
||||
|
||||
struct nvme_id_ctrl {
|
||||
unsigned short vid;
|
||||
unsigned short ssvid;
|
||||
char sn[20];
|
||||
char mn[40];
|
||||
char fr[8];
|
||||
unsigned char rab;
|
||||
unsigned char ieee[3];
|
||||
unsigned char cmic;
|
||||
unsigned char mdts;
|
||||
unsigned short cntlid;
|
||||
unsigned int ver;
|
||||
unsigned int rtd3r;
|
||||
unsigned int rtd3e;
|
||||
unsigned int oaes;
|
||||
unsigned int ctratt;
|
||||
unsigned char rsvd100[156];
|
||||
unsigned short oacs;
|
||||
unsigned char acl;
|
||||
unsigned char aerl;
|
||||
unsigned char frmw;
|
||||
unsigned char lpa;
|
||||
unsigned char elpe;
|
||||
unsigned char npss;
|
||||
unsigned char avscc;
|
||||
unsigned char apsta;
|
||||
unsigned short wctemp;
|
||||
unsigned short cctemp;
|
||||
unsigned short mtfa;
|
||||
unsigned int hmpre;
|
||||
unsigned int hmmin;
|
||||
unsigned char tnvmcap[16];
|
||||
unsigned char unvmcap[16];
|
||||
unsigned int rpmbs;
|
||||
unsigned short edstt;
|
||||
unsigned char dsto;
|
||||
unsigned char fwug;
|
||||
unsigned short kas;
|
||||
unsigned short hctma;
|
||||
unsigned short mntmt;
|
||||
unsigned short mxtmt;
|
||||
unsigned int sanicap;
|
||||
unsigned char rsvd332[180];
|
||||
unsigned char sqes;
|
||||
unsigned char cqes;
|
||||
unsigned short maxcmd;
|
||||
unsigned int nn;
|
||||
unsigned short oncs;
|
||||
unsigned short fuses;
|
||||
unsigned char fna;
|
||||
unsigned char vwc;
|
||||
unsigned short awun;
|
||||
unsigned short awupf;
|
||||
unsigned char nvscc;
|
||||
unsigned char rsvd531;
|
||||
unsigned short acwu;
|
||||
unsigned char rsvd534[2];
|
||||
unsigned int sgls;
|
||||
unsigned char rsvd540[228];
|
||||
char subnqn[256];
|
||||
unsigned char rsvd1024[768];
|
||||
unsigned int ioccsz;
|
||||
unsigned int iorcsz;
|
||||
unsigned short icdoff;
|
||||
unsigned char ctrattr;
|
||||
unsigned char msdbd;
|
||||
unsigned char rsvd1804[244];
|
||||
struct nvme_id_power_state psd[32];
|
||||
unsigned char vs[1024];
|
||||
};
|
||||
STATIC_ASSERT(sizeof(nvme_id_ctrl) == 4096);
|
||||
|
||||
struct nvme_lbaf {
|
||||
unsigned short ms;
|
||||
unsigned char ds;
|
||||
unsigned char rp;
|
||||
};
|
||||
STATIC_ASSERT(sizeof(nvme_lbaf) == 4);
|
||||
|
||||
struct nvme_id_ns {
|
||||
uint64_t nsze;
|
||||
uint64_t ncap;
|
||||
uint64_t nuse;
|
||||
unsigned char nsfeat;
|
||||
unsigned char nlbaf;
|
||||
unsigned char flbas;
|
||||
unsigned char mc;
|
||||
unsigned char dpc;
|
||||
unsigned char dps;
|
||||
unsigned char nmic;
|
||||
unsigned char rescap;
|
||||
unsigned char fpi;
|
||||
unsigned char rsvd33;
|
||||
unsigned short nawun;
|
||||
unsigned short nawupf;
|
||||
unsigned short nacwu;
|
||||
unsigned short nabsn;
|
||||
unsigned short nabo;
|
||||
unsigned short nabspf;
|
||||
unsigned char rsvd46[2];
|
||||
unsigned char nvmcap[16];
|
||||
unsigned char rsvd64[40];
|
||||
unsigned char nguid[16];
|
||||
unsigned char eui64[8];
|
||||
struct nvme_lbaf lbaf[16];
|
||||
unsigned char rsvd192[192];
|
||||
unsigned char vs[3712];
|
||||
};
|
||||
STATIC_ASSERT(sizeof(nvme_id_ns) == 4096);
|
||||
|
||||
struct nvme_smart_log {
|
||||
unsigned char critical_warning;
|
||||
unsigned char temperature[2];
|
||||
unsigned char avail_spare;
|
||||
unsigned char spare_thresh;
|
||||
unsigned char percent_used;
|
||||
unsigned char rsvd6[26];
|
||||
unsigned char data_units_read[16];
|
||||
unsigned char data_units_written[16];
|
||||
unsigned char host_reads[16];
|
||||
unsigned char host_writes[16];
|
||||
unsigned char ctrl_busy_time[16];
|
||||
unsigned char power_cycles[16];
|
||||
unsigned char power_on_hours[16];
|
||||
unsigned char unsafe_shutdowns[16];
|
||||
unsigned char media_errors[16];
|
||||
unsigned char num_err_log_entries[16];
|
||||
unsigned int warning_temp_time;
|
||||
unsigned int critical_comp_time;
|
||||
unsigned short temp_sensor[8];
|
||||
unsigned int thm_temp1_trans_count;
|
||||
unsigned int thm_temp2_trans_count;
|
||||
unsigned int thm_temp1_total_time;
|
||||
unsigned int thm_temp2_total_time;
|
||||
unsigned char rsvd232[280];
|
||||
};
|
||||
STATIC_ASSERT(sizeof(nvme_smart_log) == 512);
|
||||
|
||||
enum nvme_admin_opcode {
|
||||
//nvme_admin_delete_sq = 0x00,
|
||||
//nvme_admin_create_sq = 0x01,
|
||||
nvme_admin_get_log_page = 0x02,
|
||||
//nvme_admin_delete_cq = 0x04,
|
||||
//nvme_admin_create_cq = 0x05,
|
||||
nvme_admin_identify = 0x06,
|
||||
//nvme_admin_abort_cmd = 0x08,
|
||||
//nvme_admin_set_features = 0x09,
|
||||
//nvme_admin_get_features = 0x0a,
|
||||
//nvme_admin_async_event = 0x0c,
|
||||
//nvme_admin_ns_mgmt = 0x0d,
|
||||
//nvme_admin_activate_fw = 0x10,
|
||||
//nvme_admin_download_fw = 0x11,
|
||||
//nvme_admin_ns_attach = 0x15,
|
||||
//nvme_admin_format_nvm = 0x80,
|
||||
//nvme_admin_security_send = 0x81,
|
||||
//nvme_admin_security_recv = 0x82,
|
||||
};
|
||||
|
||||
// END: From <linux/nvme.h>
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace smartmontools
|
||||
|
||||
class nvme_device;
|
||||
|
||||
// Print NVMe debug messages?
|
||||
extern unsigned char nvme_debugmode;
|
||||
|
||||
// Read NVMe Identify Controller data structure.
|
||||
bool nvme_read_id_ctrl(nvme_device * device, smartmontools::nvme_id_ctrl & id_ctrl);
|
||||
|
||||
// Read NVMe Identify Namespace data structure for namespace NSID.
|
||||
bool nvme_read_id_ns(nvme_device * device, unsigned nsid, smartmontools::nvme_id_ns & id_ns);
|
||||
|
||||
// Read NVMe log page with identifier LID.
|
||||
unsigned nvme_read_log_page(nvme_device * device, unsigned nsid, unsigned char lid,
|
||||
void * data, unsigned size, bool lpo_sup, unsigned offset = 0);
|
||||
|
||||
// Read NVMe Error Information Log.
|
||||
unsigned nvme_read_error_log(nvme_device * device, smartmontools::nvme_error_log_page * error_log,
|
||||
unsigned num_entries, bool lpo_sup);
|
||||
|
||||
// Read NVMe SMART/Health Information log.
|
||||
bool nvme_read_smart_log(nvme_device * device, smartmontools::nvme_smart_log & smart_log);
|
||||
|
||||
#endif // NVMECMDS_H
|
|
@ -1,626 +0,0 @@
|
|||
/*
|
||||
* nvmeprint.cpp
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2016-21 Christian Franke
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#define __STDC_FORMAT_MACROS 1 // enable PRI* for C++
|
||||
|
||||
#include "nvmeprint.h"
|
||||
|
||||
const char * nvmeprint_cvsid = "$Id: nvmeprint.cpp 5218 2021-06-04 15:46:36Z chrfranke $"
|
||||
NVMEPRINT_H_CVSID;
|
||||
|
||||
#include "utility.h"
|
||||
#include "dev_interface.h"
|
||||
#include "nvmecmds.h"
|
||||
#include "atacmds.h" // dont_print_serial_number
|
||||
#include "scsicmds.h" // dStrHex()
|
||||
#include "smartctl.h"
|
||||
#include "sg_unaligned.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
using namespace smartmontools;
|
||||
|
||||
// Return true if 128 bit LE integer is != 0.
|
||||
static bool le128_is_non_zero(const unsigned char (& val)[16])
|
||||
{
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (val[i])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Format 128 bit integer for printing.
|
||||
// Add value with SI prefixes if BYTES_PER_UNIT is specified.
|
||||
static const char * le128_to_str(char (& str)[64], uint64_t hi, uint64_t lo, unsigned bytes_per_unit)
|
||||
{
|
||||
if (!hi) {
|
||||
// Up to 64-bit, print exact value
|
||||
format_with_thousands_sep(str, sizeof(str)-16, lo);
|
||||
|
||||
if (lo && bytes_per_unit && lo < 0xffffffffffffffffULL / bytes_per_unit) {
|
||||
int i = strlen(str);
|
||||
str[i++] = ' '; str[i++] = '[';
|
||||
format_capacity(str+i, (int)sizeof(str)-i-1, lo * bytes_per_unit);
|
||||
i = strlen(str);
|
||||
str[i++] = ']'; str[i] = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// More than 64-bit, prepend '~' flag on low precision
|
||||
int i = 0;
|
||||
// cppcheck-suppress knownConditionTrueFalse
|
||||
if (uint128_to_str_precision_bits() < 128)
|
||||
str[i++] = '~';
|
||||
uint128_hilo_to_str(str + i, (int)sizeof(str) - i, hi, lo);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
// Format 128 bit LE integer for printing.
|
||||
// Add value with SI prefixes if BYTES_PER_UNIT is specified.
|
||||
static const char * le128_to_str(char (& str)[64], const unsigned char (& val)[16],
|
||||
unsigned bytes_per_unit = 0)
|
||||
{
|
||||
uint64_t hi = val[15];
|
||||
for (int i = 15-1; i >= 8; i--) {
|
||||
hi <<= 8; hi += val[i];
|
||||
}
|
||||
uint64_t lo = val[7];
|
||||
for (int i = 7-1; i >= 0; i--) {
|
||||
lo <<= 8; lo += val[i];
|
||||
}
|
||||
return le128_to_str(str, hi, lo, bytes_per_unit);
|
||||
}
|
||||
|
||||
// Format capacity specified as 64bit LBA count for printing.
|
||||
static const char * lbacap_to_str(char (& str)[64], uint64_t lba_cnt, int lba_bits)
|
||||
{
|
||||
return le128_to_str(str, (lba_cnt >> (64 - lba_bits)), (lba_cnt << lba_bits), 1);
|
||||
}
|
||||
|
||||
// Output capacity specified as 64bit LBA count to JSON
|
||||
static void lbacap_to_js(const json::ref & jref, uint64_t lba_cnt, int lba_bits)
|
||||
{
|
||||
jref["blocks"].set_unsafe_uint64(lba_cnt);
|
||||
jref["bytes"].set_unsafe_uint128((lba_cnt >> (64 - lba_bits)), (lba_cnt << lba_bits));
|
||||
}
|
||||
|
||||
// Format a Kelvin temperature value in Celsius.
|
||||
static const char * kelvin_to_str(char (& str)[64], int k)
|
||||
{
|
||||
if (!k) // unsupported?
|
||||
str[0] = '-', str[1] = 0;
|
||||
else
|
||||
snprintf(str, sizeof(str), "%d", k - 273);
|
||||
return str;
|
||||
}
|
||||
|
||||
static void print_drive_info(const nvme_id_ctrl & id_ctrl, const nvme_id_ns & id_ns,
|
||||
unsigned nsid, bool show_all)
|
||||
{
|
||||
char buf[64];
|
||||
jout("Model Number: %s\n", format_char_array(buf, id_ctrl.mn));
|
||||
jglb["model_name"] = buf;
|
||||
if (!dont_print_serial_number) {
|
||||
jout("Serial Number: %s\n", format_char_array(buf, id_ctrl.sn));
|
||||
jglb["serial_number"] = buf;
|
||||
}
|
||||
|
||||
jout("Firmware Version: %s\n", format_char_array(buf, id_ctrl.fr));
|
||||
jglb["firmware_version"] = buf;
|
||||
|
||||
// Vendor and Subsystem IDs are usually equal
|
||||
if (show_all || id_ctrl.vid != id_ctrl.ssvid) {
|
||||
jout("PCI Vendor ID: 0x%04x\n", id_ctrl.vid);
|
||||
jout("PCI Vendor Subsystem ID: 0x%04x\n", id_ctrl.ssvid);
|
||||
}
|
||||
else {
|
||||
jout("PCI Vendor/Subsystem ID: 0x%04x\n", id_ctrl.vid);
|
||||
}
|
||||
jglb["nvme_pci_vendor"]["id"] = id_ctrl.vid;
|
||||
jglb["nvme_pci_vendor"]["subsystem_id"] = id_ctrl.ssvid;
|
||||
|
||||
jout("IEEE OUI Identifier: 0x%02x%02x%02x\n",
|
||||
id_ctrl.ieee[2], id_ctrl.ieee[1], id_ctrl.ieee[0]);
|
||||
jglb["nvme_ieee_oui_identifier"] = sg_get_unaligned_le(3, id_ctrl.ieee);
|
||||
|
||||
// Capacity info is optional for devices without namespace management
|
||||
if (show_all || le128_is_non_zero(id_ctrl.tnvmcap) || le128_is_non_zero(id_ctrl.unvmcap)) {
|
||||
jout("Total NVM Capacity: %s\n", le128_to_str(buf, id_ctrl.tnvmcap, 1));
|
||||
jglb["nvme_total_capacity"].set_unsafe_le128(id_ctrl.tnvmcap);
|
||||
jout("Unallocated NVM Capacity: %s\n", le128_to_str(buf, id_ctrl.unvmcap, 1));
|
||||
jglb["nvme_unallocated_capacity"].set_unsafe_le128(id_ctrl.unvmcap);
|
||||
}
|
||||
|
||||
jout("Controller ID: %d\n", id_ctrl.cntlid);
|
||||
jglb["nvme_controller_id"] = id_ctrl.cntlid;
|
||||
|
||||
if (id_ctrl.ver) { // NVMe 1.2
|
||||
int i = snprintf(buf, sizeof(buf), "%u.%u", id_ctrl.ver >> 16, (id_ctrl.ver >> 8) & 0xff);
|
||||
if (i > 0 && (id_ctrl.ver & 0xff))
|
||||
snprintf(buf+i, sizeof(buf)-i, ".%u", id_ctrl.ver & 0xff);
|
||||
}
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "<1.2");
|
||||
jout("NVMe Version: %s\n", buf);
|
||||
jglb["nvme_version"]["string"] = buf;
|
||||
jglb["nvme_version"]["value"] = id_ctrl.ver;
|
||||
|
||||
// Print namespace info if available
|
||||
jout("Number of Namespaces: %u\n", id_ctrl.nn);
|
||||
jglb["nvme_number_of_namespaces"] = id_ctrl.nn;
|
||||
|
||||
if (nsid && id_ns.nsze) {
|
||||
const char * align = &(" "[nsid < 10 ? 0 : (nsid < 100 ? 1 : 2)]);
|
||||
int fmt_lba_bits = id_ns.lbaf[id_ns.flbas & 0xf].ds;
|
||||
|
||||
json::ref jrns = jglb["nvme_namespaces"][0];
|
||||
jrns["id"] = nsid;
|
||||
|
||||
// Size and Capacity are equal if thin provisioning is not supported
|
||||
if (show_all || id_ns.ncap != id_ns.nsze || (id_ns.nsfeat & 0x01)) {
|
||||
jout("Namespace %u Size: %s%s\n", nsid, align,
|
||||
lbacap_to_str(buf, id_ns.nsze, fmt_lba_bits));
|
||||
jout("Namespace %u Capacity: %s%s\n", nsid, align,
|
||||
lbacap_to_str(buf, id_ns.ncap, fmt_lba_bits));
|
||||
}
|
||||
else {
|
||||
jout("Namespace %u Size/Capacity: %s%s\n", nsid, align,
|
||||
lbacap_to_str(buf, id_ns.nsze, fmt_lba_bits));
|
||||
}
|
||||
lbacap_to_js(jrns["size"], id_ns.nsze, fmt_lba_bits);
|
||||
lbacap_to_js(jrns["capacity"], id_ns.ncap, fmt_lba_bits);
|
||||
lbacap_to_js(jglb["user_capacity"], id_ns.ncap, fmt_lba_bits); // TODO: use nsze?
|
||||
|
||||
// Utilization may be always equal to Capacity if thin provisioning is not supported
|
||||
if (show_all || id_ns.nuse != id_ns.ncap || (id_ns.nsfeat & 0x01))
|
||||
jout("Namespace %u Utilization: %s%s\n", nsid, align,
|
||||
lbacap_to_str(buf, id_ns.nuse, fmt_lba_bits));
|
||||
lbacap_to_js(jrns["utilization"], id_ns.nuse, fmt_lba_bits);
|
||||
|
||||
jout("Namespace %u Formatted LBA Size: %s%u\n", nsid, align, (1U << fmt_lba_bits));
|
||||
jrns["formatted_lba_size"] = (1U << fmt_lba_bits);
|
||||
jglb["logical_block_size"] = (1U << fmt_lba_bits);
|
||||
|
||||
if (show_all || nonempty(id_ns.eui64, sizeof(id_ns.eui64))) {
|
||||
jout("Namespace %u IEEE EUI-64: %s%02x%02x%02x %02x%02x%02x%02x%02x\n",
|
||||
nsid, align, id_ns.eui64[0], id_ns.eui64[1], id_ns.eui64[2], id_ns.eui64[3],
|
||||
id_ns.eui64[4], id_ns.eui64[5], id_ns.eui64[6], id_ns.eui64[7]);
|
||||
jrns["eui64"]["oui"] = sg_get_unaligned_be(3, id_ns.eui64);
|
||||
jrns["eui64"]["ext_id"] = sg_get_unaligned_be(5, id_ns.eui64 + 3);
|
||||
}
|
||||
}
|
||||
|
||||
// SMART/Health Information is mandatory
|
||||
jglb["smart_support"] += { {"available", true}, {"enabled", true} };
|
||||
|
||||
jout_startup_datetime("Local Time is: ");
|
||||
}
|
||||
|
||||
// Format scaled power value.
|
||||
static const char * format_power(char (& str)[16], unsigned power, unsigned scale)
|
||||
{
|
||||
switch (scale & 0x3) {
|
||||
case 0: // not reported
|
||||
str[0] = '-'; str[1] = ' '; str[2] = 0; break;
|
||||
case 1: // 0.0001W
|
||||
snprintf(str, sizeof(str), "%u.%04uW", power / 10000, power % 10000); break;
|
||||
case 2: // 0.01W
|
||||
snprintf(str, sizeof(str), "%u.%02uW", power / 100, power % 100); break;
|
||||
default: // reserved
|
||||
str[0] = '?'; str[1] = 0; break;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static void print_drive_capabilities(const nvme_id_ctrl & id_ctrl, const nvme_id_ns & id_ns,
|
||||
unsigned nsid, bool show_all)
|
||||
{
|
||||
pout("Firmware Updates (0x%02x): %d Slot%s%s%s\n", id_ctrl.frmw,
|
||||
((id_ctrl.frmw >> 1) & 0x7), (((id_ctrl.frmw >> 1) & 0x7) != 1 ? "s" : ""),
|
||||
((id_ctrl.frmw & 0x01) ? ", Slot 1 R/O" : ""),
|
||||
((id_ctrl.frmw & 0x10) ? ", no Reset required" : ""));
|
||||
|
||||
if (show_all || id_ctrl.oacs)
|
||||
pout("Optional Admin Commands (0x%04x): %s%s%s%s%s%s%s%s%s%s%s%s\n", id_ctrl.oacs,
|
||||
(!id_ctrl.oacs ? " -" : ""),
|
||||
((id_ctrl.oacs & 0x0001) ? " Security" : ""),
|
||||
((id_ctrl.oacs & 0x0002) ? " Format" : ""),
|
||||
((id_ctrl.oacs & 0x0004) ? " Frmw_DL" : ""),
|
||||
((id_ctrl.oacs & 0x0008) ? " NS_Mngmt" : ""), // NVMe 1.2
|
||||
((id_ctrl.oacs & 0x0010) ? " Self_Test" : ""), // NVMe 1.3 ...
|
||||
((id_ctrl.oacs & 0x0020) ? " Directvs" : ""),
|
||||
((id_ctrl.oacs & 0x0040) ? " MI_Snd/Rec" : ""),
|
||||
((id_ctrl.oacs & 0x0080) ? " Vrt_Mngmt" : ""),
|
||||
((id_ctrl.oacs & 0x0100) ? " Drbl_Bf_Cfg" : ""),
|
||||
((id_ctrl.oacs & 0x0200) ? " Get_LBA_Sts" : ""), // NVMe 1.4
|
||||
((id_ctrl.oacs & ~0x03ff) ? " *Other*" : ""));
|
||||
|
||||
if (show_all || id_ctrl.oncs)
|
||||
pout("Optional NVM Commands (0x%04x): %s%s%s%s%s%s%s%s%s%s\n", id_ctrl.oncs,
|
||||
(!id_ctrl.oncs ? " -" : ""),
|
||||
((id_ctrl.oncs & 0x0001) ? " Comp" : ""),
|
||||
((id_ctrl.oncs & 0x0002) ? " Wr_Unc" : ""),
|
||||
((id_ctrl.oncs & 0x0004) ? " DS_Mngmt" : ""),
|
||||
((id_ctrl.oncs & 0x0008) ? " Wr_Zero" : ""), // NVMe 1.1 ...
|
||||
((id_ctrl.oncs & 0x0010) ? " Sav/Sel_Feat" : ""),
|
||||
((id_ctrl.oncs & 0x0020) ? " Resv" : ""),
|
||||
((id_ctrl.oncs & 0x0040) ? " Timestmp" : ""), // NVMe 1.3
|
||||
((id_ctrl.oncs & 0x0080) ? " Verify" : ""), // NVMe 1.4
|
||||
((id_ctrl.oncs & ~0x00ff) ? " *Other*" : ""));
|
||||
|
||||
if (show_all || id_ctrl.lpa)
|
||||
pout("Log Page Attributes (0x%02x): %s%s%s%s%s%s%s\n", id_ctrl.lpa,
|
||||
(!id_ctrl.lpa ? " -" : ""),
|
||||
((id_ctrl.lpa & 0x01) ? " S/H_per_NS" : ""),
|
||||
((id_ctrl.lpa & 0x02) ? " Cmd_Eff_Lg" : ""), // NVMe 1.2
|
||||
((id_ctrl.lpa & 0x04) ? " Ext_Get_Lg" : ""), // NVMe 1.2.1
|
||||
((id_ctrl.lpa & 0x08) ? " Telmtry_Lg" : ""), // NVMe 1.3
|
||||
((id_ctrl.lpa & 0x10) ? " Pers_Ev_Lg" : ""), // NVMe 1.4
|
||||
((id_ctrl.lpa & ~0x001f) ? " *Other*" : ""));
|
||||
|
||||
if (id_ctrl.mdts)
|
||||
pout("Maximum Data Transfer Size: %u Pages\n", (1U << id_ctrl.mdts));
|
||||
else if (show_all)
|
||||
pout("Maximum Data Transfer Size: -\n");
|
||||
|
||||
// Temperature thresholds are optional
|
||||
char buf[64];
|
||||
if (show_all || id_ctrl.wctemp)
|
||||
pout("Warning Comp. Temp. Threshold: %s\n", kelvin_to_str(buf, id_ctrl.wctemp));
|
||||
if (show_all || id_ctrl.cctemp)
|
||||
pout("Critical Comp. Temp. Threshold: %s\n", kelvin_to_str(buf, id_ctrl.cctemp));
|
||||
|
||||
if (nsid && (show_all || id_ns.nsfeat)) {
|
||||
const char * align = &(" "[nsid < 10 ? 0 : (nsid < 100 ? 1 : 2)]);
|
||||
pout("Namespace %u Features (0x%02x): %s%s%s%s%s%s%s%s\n", nsid, id_ns.nsfeat, align,
|
||||
(!id_ns.nsfeat ? " -" : ""),
|
||||
((id_ns.nsfeat & 0x01) ? " Thin_Prov" : ""),
|
||||
((id_ns.nsfeat & 0x02) ? " NA_Fields" : ""), // NVMe 1.2 ...
|
||||
((id_ns.nsfeat & 0x04) ? " Dea/Unw_Error" : ""),
|
||||
((id_ns.nsfeat & 0x08) ? " No_ID_Reuse" : ""), // NVMe 1.3
|
||||
((id_ns.nsfeat & 0x10) ? " NP_Fields" : ""), // NVMe 1.4
|
||||
((id_ns.nsfeat & ~0x1f) ? " *Other*" : ""));
|
||||
}
|
||||
|
||||
// Print Power States
|
||||
pout("\nSupported Power States\n");
|
||||
pout("St Op Max Active Idle RL RT WL WT Ent_Lat Ex_Lat\n");
|
||||
for (int i = 0; i <= id_ctrl.npss /* 1-based */ && i < 32; i++) {
|
||||
char p1[16], p2[16], p3[16];
|
||||
const nvme_id_power_state & ps = id_ctrl.psd[i];
|
||||
pout("%2d %c %9s %8s %8s %3d %2d %2d %2d %8u %7u\n", i,
|
||||
((ps.flags & 0x02) ? '-' : '+'),
|
||||
format_power(p1, ps.max_power, ((ps.flags & 0x01) ? 1 : 2)),
|
||||
format_power(p2, ps.active_power, ps.active_work_scale),
|
||||
format_power(p3, ps.idle_power, ps.idle_scale),
|
||||
ps.read_lat & 0x1f, ps.read_tput & 0x1f,
|
||||
ps.write_lat & 0x1f, ps.write_tput & 0x1f,
|
||||
ps.entry_lat, ps.exit_lat);
|
||||
}
|
||||
|
||||
// Print LBA sizes
|
||||
if (nsid && id_ns.lbaf[0].ds) {
|
||||
pout("\nSupported LBA Sizes (NSID 0x%x)\n", nsid);
|
||||
pout("Id Fmt Data Metadt Rel_Perf\n");
|
||||
for (int i = 0; i <= id_ns.nlbaf /* 1-based */ && i < 16; i++) {
|
||||
const nvme_lbaf & lba = id_ns.lbaf[i];
|
||||
pout("%2d %c %7u %7d %9d\n", i, (i == id_ns.flbas ? '+' : '-'),
|
||||
(1U << lba.ds), lba.ms, lba.rp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void print_critical_warning(unsigned char w)
|
||||
{
|
||||
jout("SMART overall-health self-assessment test result: %s\n",
|
||||
(!w ? "PASSED" : "FAILED!"));
|
||||
jglb["smart_status"]["passed"] = !w;
|
||||
|
||||
json::ref jref = jglb["smart_status"]["nvme"];
|
||||
jref["value"] = w;
|
||||
|
||||
if (w) {
|
||||
if (w & 0x01)
|
||||
jout("- available spare has fallen below threshold\n");
|
||||
jref["spare_below_threshold"] = !!(w & 0x01);
|
||||
if (w & 0x02)
|
||||
jout("- temperature is above or below threshold\n");
|
||||
jref["temperature_above_or_below_threshold"] = !!(w & 0x02);
|
||||
if (w & 0x04)
|
||||
jout("- NVM subsystem reliability has been degraded\n");
|
||||
jref["reliability_degraded"] = !!(w & 0x04);
|
||||
if (w & 0x08)
|
||||
jout("- media has been placed in read only mode\n");
|
||||
jref["media_read_only"] = !!(w & 0x08);
|
||||
if (w & 0x10)
|
||||
jout("- volatile memory backup device has failed\n");
|
||||
jref["volatile_memory_backup_failed"] = !!(w & 0x10);
|
||||
if (w & 0x20)
|
||||
jout("- persistent memory region has become read-only or unreliable\n");
|
||||
jref["persistent_memory_region_unreliable"] = !!(w & 0x20);
|
||||
if (w & ~0x3f)
|
||||
jout("- unknown critical warning(s) (0x%02x)\n", w & ~0x3f);
|
||||
jref["other"] = w & ~0x3f;
|
||||
}
|
||||
|
||||
jout("\n");
|
||||
}
|
||||
|
||||
static void print_smart_log(const nvme_smart_log & smart_log,
|
||||
const nvme_id_ctrl & id_ctrl, bool show_all)
|
||||
{
|
||||
json::ref jref = jglb["nvme_smart_health_information_log"];
|
||||
char buf[64];
|
||||
// jout("SMART/Health Information (NVMe Log 0x02)\n");
|
||||
// jout("Critical Warning: 0x%02x\n", smart_log.critical_warning);
|
||||
// jref["critical_warning"] = smart_log.critical_warning;
|
||||
|
||||
int k = sg_get_unaligned_le16(smart_log.temperature);
|
||||
// jout("Temperature: %s\n", kelvin_to_str(buf, k));
|
||||
// if (k) {
|
||||
// jref["temperature"] = k - 273;
|
||||
// jglb["temperature"]["current"] = k - 273;
|
||||
// }
|
||||
|
||||
// jout("Available Spare: %u%%\n", smart_log.avail_spare);
|
||||
// jref["available_spare"] = smart_log.avail_spare;
|
||||
// jout("Available Spare Threshold: %u%%\n", smart_log.spare_thresh);
|
||||
// jref["available_spare_threshold"] = smart_log.spare_thresh;
|
||||
// jout("Percentage Used: %u%%\n", smart_log.percent_used);
|
||||
// jref["percentage_used"] = smart_log.percent_used;
|
||||
// jout("Data Units Read: %s\n", le128_to_str(buf, smart_log.data_units_read, 1000*512));
|
||||
// jref["data_units_read"].set_unsafe_le128(smart_log.data_units_read);
|
||||
// jout("Data Units Written: %s\n", le128_to_str(buf, smart_log.data_units_written, 1000*512));
|
||||
// jref["data_units_written"].set_unsafe_le128(smart_log.data_units_written);
|
||||
// jout("Host Read Commands: %s\n", le128_to_str(buf, smart_log.host_reads));
|
||||
// jref["host_reads"].set_unsafe_le128(smart_log.host_reads);
|
||||
// jout("Host Write Commands: %s\n", le128_to_str(buf, smart_log.host_writes));
|
||||
// jref["host_writes"].set_unsafe_le128(smart_log.host_writes);
|
||||
// jout("Controller Busy Time: %s\n", le128_to_str(buf, smart_log.ctrl_busy_time));
|
||||
// jref["controller_busy_time"].set_unsafe_le128(smart_log.ctrl_busy_time);
|
||||
// jout("Power Cycles: %s\n", le128_to_str(buf, smart_log.power_cycles));
|
||||
// jref["power_cycles"].set_unsafe_le128(smart_log.power_cycles);
|
||||
// jglb["power_cycle_count"].set_if_safe_le128(smart_log.power_cycles);
|
||||
// jout("Power On Hours: %s\n", le128_to_str(buf, smart_log.power_on_hours));
|
||||
// jref["power_on_hours"].set_unsafe_le128(smart_log.power_on_hours);
|
||||
// jglb["power_on_time"]["hours"].set_if_safe_le128(smart_log.power_on_hours);
|
||||
// jout("Unsafe Shutdowns: %s\n", le128_to_str(buf, smart_log.unsafe_shutdowns));
|
||||
// jref["unsafe_shutdowns"].set_unsafe_le128(smart_log.unsafe_shutdowns);
|
||||
// jout("Media and Data Integrity Errors: %s\n", le128_to_str(buf, smart_log.media_errors));
|
||||
// jref["media_errors"].set_unsafe_le128(smart_log.media_errors);
|
||||
// jout("Error Information Log Entries: %s\n", le128_to_str(buf, smart_log.num_err_log_entries));
|
||||
// jref["num_err_log_entries"].set_unsafe_le128(smart_log.num_err_log_entries);
|
||||
|
||||
// // Temperature thresholds are optional
|
||||
// if (show_all || id_ctrl.wctemp || smart_log.warning_temp_time) {
|
||||
// jout("Warning Comp. Temperature Time: %d\n", smart_log.warning_temp_time);
|
||||
// jref["warning_temp_time"] = smart_log.warning_temp_time;
|
||||
// }
|
||||
// if (show_all || id_ctrl.cctemp || smart_log.critical_comp_time) {
|
||||
// jout("Critical Comp. Temperature Time: %d\n", smart_log.critical_comp_time);
|
||||
// jref["critical_comp_time"] = smart_log.critical_comp_time;
|
||||
// }
|
||||
|
||||
// Temperature sensors are optional
|
||||
for (int i = 0; i < 8; i++) {
|
||||
k = smart_log.temp_sensor[i];
|
||||
if (show_all || k) {
|
||||
nvmeTemp = kelvin_to_str(buf, k);
|
||||
// jout("Temperature Sensor %d: %s\n", i + 1,
|
||||
// nvmeTemp.c_str());
|
||||
if (k)
|
||||
jref["temperature_sensors"][i] = k - 273;
|
||||
}
|
||||
}
|
||||
// if (show_all || smart_log.thm_temp1_trans_count)
|
||||
// pout("Thermal Temp. 1 Transition Count: %d\n", smart_log.thm_temp1_trans_count);
|
||||
// if (show_all || smart_log.thm_temp2_trans_count)
|
||||
// pout("Thermal Temp. 2 Transition Count: %d\n", smart_log.thm_temp2_trans_count);
|
||||
// if (show_all || smart_log.thm_temp1_total_time)
|
||||
// pout("Thermal Temp. 1 Total Time: %d\n", smart_log.thm_temp1_total_time);
|
||||
// if (show_all || smart_log.thm_temp2_total_time)
|
||||
// pout("Thermal Temp. 2 Total Time: %d\n", smart_log.thm_temp2_total_time);
|
||||
// pout("\n");
|
||||
}
|
||||
|
||||
static void print_error_log(const nvme_error_log_page * error_log,
|
||||
unsigned read_entries, unsigned max_entries)
|
||||
{
|
||||
pout("Error Information (NVMe Log 0x01, %u of %u entries)\n",
|
||||
read_entries, max_entries);
|
||||
|
||||
// Search last valid entry
|
||||
unsigned valid_entries = read_entries;
|
||||
while (valid_entries && !error_log[valid_entries-1].error_count)
|
||||
valid_entries--;
|
||||
|
||||
if (!valid_entries) {
|
||||
pout("No Errors Logged\n\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pout("Num ErrCount SQId CmdId Status PELoc LBA NSID VS\n");
|
||||
int unused = 0;
|
||||
for (unsigned i = 0; i < valid_entries; i++) {
|
||||
const nvme_error_log_page & e = error_log[i];
|
||||
if (!e.error_count) {
|
||||
// unused or invalid entry
|
||||
unused++;
|
||||
continue;
|
||||
}
|
||||
if (unused) {
|
||||
pout(" - [%d unused entr%s]\n", unused, (unused == 1 ? "y" : "ies"));
|
||||
unused = 0;
|
||||
}
|
||||
|
||||
char sq[16] = "-", cm[16] = "-", st[16] = "-", pe[16] = "-";
|
||||
char lb[32] = "-", ns[16] = "-", vs[8] = "-";
|
||||
if (e.sqid != 0xffff)
|
||||
snprintf(sq, sizeof(sq), "%d", e.sqid);
|
||||
if (e.cmdid != 0xffff)
|
||||
snprintf(cm, sizeof(cm), "0x%04x", e.cmdid);
|
||||
if (e.status_field != 0xffff)
|
||||
snprintf(st, sizeof(st), "0x%04x", e.status_field);
|
||||
if (e.parm_error_location != 0xffff)
|
||||
snprintf(pe, sizeof(pe), "0x%03x", e.parm_error_location);
|
||||
if (e.lba != 0xffffffffffffffffULL)
|
||||
snprintf(lb, sizeof(lb), "%" PRIu64, e.lba);
|
||||
if (e.nsid != 0xffffffffU)
|
||||
snprintf(ns, sizeof(ns), "%u", e.nsid);
|
||||
if (e.vs != 0x00)
|
||||
snprintf(vs, sizeof(vs), "0x%02x", e.vs);
|
||||
|
||||
pout("%3u %10" PRIu64 " %5s %7s %7s %6s %12s %5s %5s\n",
|
||||
i, e.error_count, sq, cm, st, pe, lb, ns, vs);
|
||||
}
|
||||
|
||||
if (valid_entries == read_entries && read_entries < max_entries)
|
||||
pout("... (%u entries not read)\n", max_entries - read_entries);
|
||||
pout("\n");
|
||||
}
|
||||
|
||||
int nvmePrintMain(nvme_device * device, const nvme_print_options & options)
|
||||
{
|
||||
if (!( options.drive_info || options.drive_capabilities
|
||||
|| options.smart_check_status || options.smart_vendor_attrib
|
||||
|| options.error_log_entries || options.log_page_size )) {
|
||||
pout("NVMe device successfully opened\n\n"
|
||||
"Use 'smartctl -a' (or '-x') to print SMART (and more) information\n\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Show unset optional values only if debugging is enabled
|
||||
bool show_all = (nvme_debugmode > 0);
|
||||
|
||||
// Read Identify Controller always
|
||||
nvme_id_ctrl id_ctrl;
|
||||
if (!nvme_read_id_ctrl(device, id_ctrl)) {
|
||||
jerr("Read NVMe Identify Controller failed: %s\n", device->get_errmsg());
|
||||
return FAILID;
|
||||
}
|
||||
|
||||
// Print Identify Controller/Namespace info
|
||||
if (options.drive_info || options.drive_capabilities) {
|
||||
pout("=== START OF INFORMATION SECTION ===\n");
|
||||
nvme_id_ns id_ns; memset(&id_ns, 0, sizeof(id_ns));
|
||||
|
||||
unsigned nsid = device->get_nsid();
|
||||
if (nsid == 0xffffffffU) {
|
||||
// Broadcast namespace
|
||||
if (id_ctrl.nn == 1) {
|
||||
// No namespace management, get size from single namespace
|
||||
nsid = 1;
|
||||
if (!nvme_read_id_ns(device, nsid, id_ns))
|
||||
nsid = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Identify current namespace
|
||||
if (!nvme_read_id_ns(device, nsid, id_ns)) {
|
||||
jerr("Read NVMe Identify Namespace 0x%x failed: %s\n", nsid, device->get_errmsg());
|
||||
return FAILID;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.drive_info)
|
||||
print_drive_info(id_ctrl, id_ns, nsid, show_all);
|
||||
if (options.drive_capabilities)
|
||||
print_drive_capabilities(id_ctrl, id_ns, nsid, show_all);
|
||||
pout("\n");
|
||||
}
|
||||
|
||||
// if ( options.smart_check_status || options.smart_vendor_attrib
|
||||
// || options.error_log_entries)
|
||||
// pout("=== START OF SMART DATA SECTION ===\n");
|
||||
|
||||
// Print SMART Status and SMART/Health Information
|
||||
int retval = 0;
|
||||
if (options.smart_check_status || options.smart_vendor_attrib) {
|
||||
nvme_smart_log smart_log;
|
||||
if (!nvme_read_smart_log(device, smart_log)) {
|
||||
jerr("Read NVMe SMART/Health Information failed: %s\n\n", device->get_errmsg());
|
||||
return FAILSMART;
|
||||
}
|
||||
|
||||
if (options.smart_check_status) {
|
||||
print_critical_warning(smart_log.critical_warning);
|
||||
if (smart_log.critical_warning)
|
||||
retval |= FAILSTATUS;
|
||||
}
|
||||
|
||||
if (options.smart_vendor_attrib) {
|
||||
print_smart_log(smart_log, id_ctrl, show_all);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for Log Page Offset support
|
||||
bool lpo_sup = !!(id_ctrl.lpa & 0x04);
|
||||
|
||||
// Print Error Information Log
|
||||
if (options.error_log_entries) {
|
||||
unsigned max_entries = id_ctrl.elpe + 1; // 0's based value
|
||||
unsigned want_entries = options.error_log_entries;
|
||||
if (want_entries > max_entries)
|
||||
want_entries = max_entries;
|
||||
raw_buffer error_log_buf(want_entries * sizeof(nvme_error_log_page));
|
||||
nvme_error_log_page * error_log =
|
||||
reinterpret_cast<nvme_error_log_page *>(error_log_buf.data());
|
||||
|
||||
unsigned read_entries = nvme_read_error_log(device, error_log, want_entries, lpo_sup);
|
||||
if (!read_entries) {
|
||||
jerr("Read %u entries from Error Information Log failed: %s\n\n",
|
||||
want_entries, device->get_errmsg());
|
||||
return retval | FAILSMART;
|
||||
}
|
||||
if (read_entries < want_entries)
|
||||
jerr("Read Error Information Log failed, %u entries missing: %s\n",
|
||||
want_entries - read_entries, device->get_errmsg());
|
||||
|
||||
print_error_log(error_log, read_entries, max_entries);
|
||||
}
|
||||
|
||||
// Dump log page
|
||||
if (options.log_page_size) {
|
||||
// Align size to dword boundary
|
||||
unsigned size = ((options.log_page_size + 4-1) / 4) * 4;
|
||||
raw_buffer log_buf(size);
|
||||
|
||||
unsigned nsid;
|
||||
switch (options.log_page) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
nsid = 0xffffffff;
|
||||
break;
|
||||
default:
|
||||
nsid = device->get_nsid();
|
||||
break;
|
||||
}
|
||||
unsigned read_bytes = nvme_read_log_page(device, nsid, options.log_page, log_buf.data(),
|
||||
size, lpo_sup);
|
||||
if (!read_bytes) {
|
||||
jerr("Read NVMe Log 0x%02x failed: %s\n\n", options.log_page, device->get_errmsg());
|
||||
return retval | FAILSMART;
|
||||
}
|
||||
if (read_bytes < size)
|
||||
jerr("Read NVMe Log 0x%02x failed, 0x%x bytes missing: %s\n",
|
||||
options.log_page, size - read_bytes, device->get_errmsg());
|
||||
|
||||
pout("NVMe Log 0x%02x (0x%04x bytes)\n", options.log_page, read_bytes);
|
||||
dStrHex(log_buf.data(), read_bytes, 0);
|
||||
pout("\n");
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* nvmeprint.h
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2016-21 Christian Franke
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef NVMEPRINT_H
|
||||
#define NVMEPRINT_H
|
||||
|
||||
#define NVMEPRINT_H_CVSID "$Id: nvmeprint.h 5183 2021-01-24 16:40:20Z chrfranke $"
|
||||
|
||||
#include "nvmecmds.h"
|
||||
|
||||
// options for nvmePrintMain
|
||||
struct nvme_print_options
|
||||
{
|
||||
bool drive_info = false;
|
||||
bool drive_capabilities = false;
|
||||
bool smart_check_status = false;
|
||||
bool smart_vendor_attrib = false;
|
||||
unsigned error_log_entries = 0;
|
||||
unsigned char log_page = 0;
|
||||
unsigned log_page_size = 0;
|
||||
};
|
||||
|
||||
int nvmePrintMain(nvme_device *device, const nvme_print_options &options);
|
||||
|
||||
#endif // NVMEPRINT_H
|
File diff suppressed because it is too large
Load Diff
|
@ -1,409 +0,0 @@
|
|||
/*
|
||||
* os_linux.h
|
||||
*
|
||||
* Home page of code is: http://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2003-8 Bruce Allen
|
||||
*
|
||||
* Derived from code that was
|
||||
*
|
||||
* Written By: Adam Radford <linux@3ware.com>
|
||||
* Modifications By: Joel Jacobson <linux@3ware.com>
|
||||
* Arnaldo Carvalho de Melo <acme@conectiva.com.br>
|
||||
* Brad Strand <linux@3ware.com>
|
||||
*
|
||||
* Copyright (C) 1999-2003 3ware Inc.
|
||||
*
|
||||
* Kernel compatibility By: Andre Hedrick <andre@suse.com>
|
||||
* Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef OS_LINUX_H_
|
||||
#define OS_LINUX_H_
|
||||
|
||||
#define OS_LINUX_H_CVSID "$Id: os_linux.h 4842 2018-12-02 16:07:26Z chrfranke $\n"
|
||||
|
||||
/*
|
||||
The following definitions/macros/prototypes are used for three
|
||||
different interfaces, referred to as "the three cases" below.
|
||||
CONTROLLER_3WARE_678K -- 6000, 7000, and 8000 controllers via /dev/sd?
|
||||
CONTROLLER_3WARE_678K_CHAR -- 6000, 7000, and 8000 controllers via /dev/twe?
|
||||
CONTROLLER_3WARE_9000_CHAR -- 9000 controllers via /dev/twa?
|
||||
*/
|
||||
|
||||
// USED FOR ALL THREE CASES
|
||||
|
||||
#define u32 unsigned int
|
||||
#define TW_OP_ATA_PASSTHRU 0x11
|
||||
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
||||
|
||||
#pragma pack(1)
|
||||
/* Scatter gather list entry */
|
||||
typedef struct TAG_TW_SG_Entry
|
||||
{
|
||||
unsigned int address;
|
||||
unsigned int length;
|
||||
} TW_SG_Entry;
|
||||
|
||||
/* Command header for ATA pass-thru. Note that for different
|
||||
drivers/interfaces the length of sg_list (here TW_ATA_PASS_SGL_MAX)
|
||||
is different. But it can be taken as same for all three cases
|
||||
because it's never used to define any other structures, and we
|
||||
never use anything in the sg_list or beyond! */
|
||||
|
||||
#define TW_ATA_PASS_SGL_MAX 60
|
||||
|
||||
typedef struct TAG_TW_Passthru
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned char opcode : 5;
|
||||
unsigned char sgloff : 3;
|
||||
} byte0;
|
||||
unsigned char size;
|
||||
unsigned char request_id;
|
||||
unsigned char unit;
|
||||
unsigned char status; // On return, contains 3ware STATUS register
|
||||
unsigned char flags;
|
||||
unsigned short param;
|
||||
unsigned short features; // On return, contains ATA ERROR register
|
||||
unsigned short sector_count;
|
||||
unsigned short sector_num;
|
||||
unsigned short cylinder_lo;
|
||||
unsigned short cylinder_hi;
|
||||
unsigned char drive_head;
|
||||
unsigned char command; // On return, contains ATA STATUS register
|
||||
TW_SG_Entry sg_list[TW_ATA_PASS_SGL_MAX];
|
||||
unsigned char padding[12];
|
||||
} TW_Passthru;
|
||||
|
||||
// the following are for the SCSI interface only
|
||||
|
||||
// Ioctl buffer: Note that this defn has changed in kernel tree...
|
||||
// Total size is 1041 bytes -- this is really weird
|
||||
|
||||
#define TW_IOCTL 0x80
|
||||
#define TW_ATA_PASSTHRU 0x1e
|
||||
|
||||
// Adam -- should this be #pramga packed? Otherwise table_id gets
|
||||
// moved for byte alignment. Without packing, input passthru for SCSI
|
||||
// ioctl is 31 bytes in. With packing it is 30 bytes in.
|
||||
typedef struct TAG_TW_Ioctl
|
||||
{
|
||||
int input_length;
|
||||
int output_length;
|
||||
unsigned char cdb[16];
|
||||
unsigned char opcode;
|
||||
// This one byte of padding is missing from the typedefs in the
|
||||
// kernel code, but it is indeed present. We put it explicitly
|
||||
// here, so that the structure can be packed. Adam agrees with
|
||||
// this.
|
||||
unsigned char packing;
|
||||
unsigned short table_id;
|
||||
unsigned char parameter_id;
|
||||
unsigned char parameter_size_bytes;
|
||||
unsigned char unit_index;
|
||||
// Size up to here is 30 bytes + 1 padding!
|
||||
unsigned char input_data[499];
|
||||
// Reserve lots of extra space for commands that set Sector Count
|
||||
// register to large values
|
||||
unsigned char output_data[512]; // starts 530 bytes in!
|
||||
// two more padding bytes here if structure NOT packed.
|
||||
} TW_Ioctl;
|
||||
|
||||
/* Ioctl buffer output -- SCSI interface only! */
|
||||
typedef struct TAG_TW_Output
|
||||
{
|
||||
int padding[2];
|
||||
char output_data[512];
|
||||
} TW_Output;
|
||||
|
||||
// What follows is needed for 9000 char interface only
|
||||
|
||||
#define TW_IOCTL_FIRMWARE_PASS_THROUGH 0x108
|
||||
#define TW_MAX_SGL_LENGTH_9000 61
|
||||
|
||||
typedef struct TAG_TW_Ioctl_Driver_Command_9000
|
||||
{
|
||||
unsigned int control_code;
|
||||
unsigned int status;
|
||||
unsigned int unique_id;
|
||||
unsigned int sequence_id;
|
||||
unsigned int os_specific;
|
||||
unsigned int buffer_length;
|
||||
} TW_Ioctl_Driver_Command_9000;
|
||||
|
||||
/* Command Packet */
|
||||
typedef struct TW_Command_9000
|
||||
{
|
||||
/* First DWORD */
|
||||
struct
|
||||
{
|
||||
unsigned char opcode : 5;
|
||||
unsigned char sgl_offset : 3;
|
||||
} byte0;
|
||||
unsigned char size;
|
||||
unsigned char request_id;
|
||||
struct
|
||||
{
|
||||
unsigned char unit : 4;
|
||||
unsigned char host_id : 4;
|
||||
} byte3;
|
||||
/* Second DWORD */
|
||||
unsigned char status;
|
||||
unsigned char flags;
|
||||
union
|
||||
{
|
||||
unsigned short block_count;
|
||||
unsigned short parameter_count;
|
||||
unsigned short message_credits;
|
||||
} byte6;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 lba;
|
||||
TW_SG_Entry sgl[TW_MAX_SGL_LENGTH_9000];
|
||||
u32 padding;
|
||||
} io;
|
||||
struct
|
||||
{
|
||||
TW_SG_Entry sgl[TW_MAX_SGL_LENGTH_9000];
|
||||
u32 padding[2];
|
||||
} param;
|
||||
struct
|
||||
{
|
||||
u32 response_queue_pointer;
|
||||
u32 padding[125]; /* pad entire structure to 512 bytes */
|
||||
} init_connection;
|
||||
struct
|
||||
{
|
||||
char version[504];
|
||||
} ioctl_miniport_version;
|
||||
} byte8;
|
||||
} TW_Command_9000;
|
||||
|
||||
/* Command Packet for 9000+ controllers */
|
||||
typedef struct TAG_TW_Command_Apache
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned char opcode : 5;
|
||||
unsigned char reserved : 3;
|
||||
} command;
|
||||
unsigned char unit;
|
||||
unsigned short request_id;
|
||||
unsigned char sense_length;
|
||||
unsigned char sgl_offset;
|
||||
unsigned short sgl_entries;
|
||||
unsigned char cdb[16];
|
||||
TW_SG_Entry sg_list[TW_MAX_SGL_LENGTH_9000];
|
||||
} TW_Command_Apache;
|
||||
|
||||
/* New command packet header */
|
||||
typedef struct TAG_TW_Command_Apache_Header
|
||||
{
|
||||
unsigned char sense_data[18];
|
||||
struct
|
||||
{
|
||||
char reserved[4];
|
||||
unsigned short error;
|
||||
unsigned char status;
|
||||
struct
|
||||
{
|
||||
unsigned char severity : 3;
|
||||
unsigned char reserved : 5;
|
||||
} substatus_block;
|
||||
} status_block;
|
||||
unsigned char err_specific_desc[102];
|
||||
} TW_Command_Apache_Header;
|
||||
|
||||
/* This struct is a union of the 2 command packets */
|
||||
typedef struct TAG_TW_Command_Full_9000
|
||||
{
|
||||
TW_Command_Apache_Header header;
|
||||
union
|
||||
{
|
||||
TW_Command_9000 oldcommand;
|
||||
TW_Command_Apache newcommand;
|
||||
} command;
|
||||
unsigned char padding[384]; /* Pad to 1024 bytes */
|
||||
} TW_Command_Full_9000;
|
||||
|
||||
typedef struct TAG_TW_Ioctl_Apache
|
||||
{
|
||||
TW_Ioctl_Driver_Command_9000 driver_command;
|
||||
char padding[488];
|
||||
TW_Command_Full_9000 firmware_command;
|
||||
char data_buffer[1];
|
||||
// three bytes of padding here if structure not packed!
|
||||
} TW_Ioctl_Buf_Apache;
|
||||
|
||||
// START OF DEFINITIONS FOR THE CHARACTER INTERFACE TO THE
|
||||
// 6000/7000/8000 drivers
|
||||
|
||||
#define TW_MAX_SGL_LENGTH 62
|
||||
#define TW_CMD_PACKET_WITH_DATA 0x1f
|
||||
|
||||
/* Command Packet */
|
||||
typedef struct TW_Command
|
||||
{
|
||||
/* First DWORD */
|
||||
struct
|
||||
{
|
||||
unsigned char opcode : 5;
|
||||
unsigned char sgl_offset : 3;
|
||||
} byte0;
|
||||
unsigned char size;
|
||||
unsigned char request_id;
|
||||
struct
|
||||
{
|
||||
unsigned char unit : 4;
|
||||
unsigned char host_id : 4;
|
||||
} byte3;
|
||||
/* Second DWORD */
|
||||
unsigned char status;
|
||||
unsigned char flags;
|
||||
union
|
||||
{
|
||||
unsigned short block_count;
|
||||
unsigned short parameter_count;
|
||||
unsigned short message_credits;
|
||||
} byte6;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 lba;
|
||||
TW_SG_Entry sgl[TW_MAX_SGL_LENGTH];
|
||||
u32 padding; /* pad to 512 bytes */
|
||||
} io;
|
||||
struct
|
||||
{
|
||||
TW_SG_Entry sgl[TW_MAX_SGL_LENGTH];
|
||||
u32 padding[2];
|
||||
} param;
|
||||
struct
|
||||
{
|
||||
u32 response_queue_pointer;
|
||||
u32 padding[125];
|
||||
} init_connection;
|
||||
struct
|
||||
{
|
||||
char version[504];
|
||||
} ioctl_miniport_version;
|
||||
} byte8;
|
||||
} TW_Command;
|
||||
|
||||
typedef struct TAG_TW_New_Ioctl
|
||||
{
|
||||
unsigned int data_buffer_length;
|
||||
unsigned char padding[508];
|
||||
TW_Command firmware_command;
|
||||
char data_buffer[1];
|
||||
// three bytes of padding here
|
||||
} TW_New_Ioctl;
|
||||
#pragma pack()
|
||||
|
||||
#if 0
|
||||
// Useful for checking/understanding packing of 3ware data structures
|
||||
// above.
|
||||
void my(int x, char *y){
|
||||
printf("The size of %30s is: %5d\n",y, x);
|
||||
return;
|
||||
}
|
||||
|
||||
int main() {
|
||||
TW_Ioctl tmp;
|
||||
my(sizeof(TW_SG_Entry),"TW_SG_Entry");
|
||||
my(sizeof(TW_Passthru),"TW_Passthru");
|
||||
my(sizeof(TW_Ioctl),"TW_Ioctl");
|
||||
my(sizeof(TW_Output),"TW_Output");
|
||||
my(sizeof(TW_Ioctl_Driver_Command_9000),"TW_Ioctl_Driver_Command_9000");
|
||||
my(sizeof(TW_Command_9000),"TW_Command_9000");
|
||||
my(sizeof(TW_Command_Apache),"TW_Command_Apache");
|
||||
my(sizeof(TW_Command_Apache_Header),"TW_Command_Apache_Header");
|
||||
my(sizeof(TW_Command_Full_9000),"TW_Command_Full_9000");
|
||||
my(sizeof(TW_Ioctl_Buf_Apache),"TW_Ioctl_Buf_Apache");
|
||||
my(sizeof(TW_Command),"TW_Command");
|
||||
my(sizeof(TW_New_Ioctl),"TW_New_Ioctl");
|
||||
printf("TW_Ioctl.table_id - start = %d (irrelevant)\n",
|
||||
(void *)&tmp.table_id - (void *)&tmp);
|
||||
printf("TW_Ioctl.input_data - start = %d (input passthru location)\n",
|
||||
(void *)&tmp.input_data - (void *)&tmp);
|
||||
printf("TW_Ioctl.output_data - start = %d (irrelevant)\n",
|
||||
(void *)&tmp.output_data - (void *)&tmp);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// The following definitions are from hdreg.h in the kernel source
|
||||
// tree. They don't carry any Copyright statements, but I think they
|
||||
// are primarily from Mark Lord and Andre Hedrick.
|
||||
typedef unsigned char task_ioreg_t;
|
||||
|
||||
typedef struct hd_drive_task_hdr
|
||||
{
|
||||
task_ioreg_t data;
|
||||
task_ioreg_t feature;
|
||||
task_ioreg_t sector_count;
|
||||
task_ioreg_t sector_number;
|
||||
task_ioreg_t low_cylinder;
|
||||
task_ioreg_t high_cylinder;
|
||||
task_ioreg_t device_head;
|
||||
task_ioreg_t command;
|
||||
} task_struct_t;
|
||||
|
||||
typedef union ide_reg_valid_s
|
||||
{
|
||||
unsigned all : 16;
|
||||
struct
|
||||
{
|
||||
unsigned data : 1;
|
||||
unsigned error_feature : 1;
|
||||
unsigned sector : 1;
|
||||
unsigned nsector : 1;
|
||||
unsigned lcyl : 1;
|
||||
unsigned hcyl : 1;
|
||||
unsigned select : 1;
|
||||
unsigned status_command : 1;
|
||||
unsigned data_hob : 1;
|
||||
unsigned error_feature_hob : 1;
|
||||
unsigned sector_hob : 1;
|
||||
unsigned nsector_hob : 1;
|
||||
unsigned lcyl_hob : 1;
|
||||
unsigned hcyl_hob : 1;
|
||||
unsigned select_hob : 1;
|
||||
unsigned control_hob : 1;
|
||||
} b;
|
||||
} ide_reg_valid_t;
|
||||
|
||||
typedef struct ide_task_request_s
|
||||
{
|
||||
task_ioreg_t io_ports[8];
|
||||
task_ioreg_t hob_ports[8];
|
||||
ide_reg_valid_t out_flags;
|
||||
ide_reg_valid_t in_flags;
|
||||
int data_phase;
|
||||
int req_cmd;
|
||||
unsigned long out_size;
|
||||
unsigned long in_size;
|
||||
} ide_task_request_t;
|
||||
|
||||
#define TASKFILE_NO_DATA 0x0000
|
||||
#define TASKFILE_IN 0x0001
|
||||
#define TASKFILE_OUT 0x0004
|
||||
#define HDIO_DRIVE_TASK_HDR_SIZE 8 * sizeof(task_ioreg_t)
|
||||
#define IDE_DRIVE_TASK_NO_DATA 0
|
||||
#define IDE_DRIVE_TASK_IN 2
|
||||
#define IDE_DRIVE_TASK_OUT 3
|
||||
#define HDIO_DRIVE_CMD 0x031f
|
||||
#define HDIO_DRIVE_TASK 0x031e
|
||||
#define HDIO_DRIVE_TASKFILE 0x031d
|
||||
#define HDIO_GET_IDENTITY 0x030d
|
||||
|
||||
#define HPTIO_CTL 0x03ff // ioctl interface for HighPoint raid device
|
||||
|
||||
#endif /* OS_LINUX_H_ */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,536 +0,0 @@
|
|||
/*
|
||||
* scsicmds.h
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2002-8 Bruce Allen
|
||||
* Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
|
||||
* Copyright (C) 2003-18 Douglas Gilbert <dgilbert@interlog.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
*
|
||||
* N.B. What was formerly known as "SMART" are now called "informational
|
||||
* exceptions" in recent t10.org drafts (i.e. recent SCSI).
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCSICMDS_H_
|
||||
#define SCSICMDS_H_
|
||||
|
||||
#define SCSICMDS_H_CVSID "$Id: scsicmds.h 5337 2022-02-27 07:53:55Z dpgilbert $\n"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/* #define SCSI_DEBUG 1 */ /* Comment out to disable command debugging */
|
||||
|
||||
/* Following conditional defines just in case OS already has them defined.
|
||||
* If they are defined we hope they are defined correctly (for SCSI). */
|
||||
#ifndef TEST_UNIT_READY
|
||||
#define TEST_UNIT_READY 0x0
|
||||
#endif
|
||||
#ifndef LOG_SELECT
|
||||
#define LOG_SELECT 0x4c
|
||||
#endif
|
||||
#ifndef LOG_SENSE
|
||||
#define LOG_SENSE 0x4d
|
||||
#endif
|
||||
#ifndef MODE_SENSE
|
||||
#define MODE_SENSE 0x1a
|
||||
#endif
|
||||
#ifndef MODE_SENSE_10
|
||||
#define MODE_SENSE_10 0x5a
|
||||
#endif
|
||||
#ifndef MODE_SELECT
|
||||
#define MODE_SELECT 0x15
|
||||
#endif
|
||||
#ifndef MODE_SELECT_10
|
||||
#define MODE_SELECT_10 0x55
|
||||
#endif
|
||||
#ifndef INQUIRY
|
||||
#define INQUIRY 0x12
|
||||
#endif
|
||||
#ifndef REQUEST_SENSE
|
||||
#define REQUEST_SENSE 0x03
|
||||
#endif
|
||||
#ifndef RECEIVE_DIAGNOSTIC
|
||||
#define RECEIVE_DIAGNOSTIC 0x1c
|
||||
#endif
|
||||
#ifndef SEND_DIAGNOSTIC
|
||||
#define SEND_DIAGNOSTIC 0x1d
|
||||
#endif
|
||||
#ifndef READ_DEFECT_10
|
||||
#define READ_DEFECT_10 0x37
|
||||
#endif
|
||||
#ifndef READ_DEFECT_12
|
||||
#define READ_DEFECT_12 0xb7
|
||||
#endif
|
||||
#ifndef START_STOP_UNIT /* SSU */
|
||||
#define START_STOP_UNIT 0x1b
|
||||
#endif
|
||||
#ifndef REPORT_LUNS
|
||||
#define REPORT_LUNS 0xa0
|
||||
#endif
|
||||
#ifndef READ_CAPACITY_10
|
||||
#define READ_CAPACITY_10 0x25
|
||||
#endif
|
||||
#ifndef READ_CAPACITY_16
|
||||
#define READ_CAPACITY_16 0x9e
|
||||
#endif
|
||||
#ifndef SAI_READ_CAPACITY_16 /* service action for READ_CAPACITY_16 */
|
||||
#define SAI_READ_CAPACITY_16 0x10
|
||||
#endif
|
||||
|
||||
#ifndef SAT_ATA_PASSTHROUGH_12
|
||||
#define SAT_ATA_PASSTHROUGH_12 0xa1
|
||||
#endif
|
||||
#ifndef SAT_ATA_PASSTHROUGH_16
|
||||
#define SAT_ATA_PASSTHROUGH_16 0x85
|
||||
#endif
|
||||
|
||||
#define DXFER_NONE 0
|
||||
#define DXFER_FROM_DEVICE 1
|
||||
#define DXFER_TO_DEVICE 2
|
||||
|
||||
struct scsi_cmnd_io
|
||||
{
|
||||
uint8_t *cmnd; /* [in]: ptr to SCSI command block (cdb) */
|
||||
size_t cmnd_len; /* [in]: number of bytes in SCSI command */
|
||||
int dxfer_dir; /* [in]: DXFER_NONE, DXFER_FROM_DEVICE, or
|
||||
DXFER_TO_DEVICE */
|
||||
uint8_t *dxferp; /* [in]: ptr to outgoing or incoming data buffer */
|
||||
size_t dxfer_len; /* [in]: bytes to be transferred to/from dxferp */
|
||||
uint8_t *sensep; /* [in]: ptr to sense buffer, filled when
|
||||
CHECK CONDITION status occurs */
|
||||
size_t max_sense_len; /* [in]: max number of bytes to write to sensep */
|
||||
unsigned timeout; /* [in]: seconds, 0-> default timeout (60 seconds?) */
|
||||
size_t resp_sense_len; /* [out]: sense buffer length written */
|
||||
uint8_t scsi_status; /* [out]: 0->ok, 2->CHECK CONDITION, etc ... */
|
||||
int resid; /* [out]: Number of bytes requested to be transferred
|
||||
less actual number transferred (0 if not
|
||||
supported) */
|
||||
};
|
||||
|
||||
struct scsi_sense_disect
|
||||
{
|
||||
uint8_t resp_code;
|
||||
uint8_t sense_key;
|
||||
uint8_t asc;
|
||||
uint8_t ascq;
|
||||
int progress; /* -1 -> N/A, 0-65535 -> available */
|
||||
};
|
||||
|
||||
/* Useful data from Informational Exception Control mode page (0x1c) */
|
||||
#define SCSI_IECMP_RAW_LEN 64
|
||||
struct scsi_iec_mode_page
|
||||
{
|
||||
uint8_t requestedCurrent;
|
||||
uint8_t gotCurrent;
|
||||
uint8_t requestedChangeable;
|
||||
uint8_t gotChangeable;
|
||||
uint8_t modese_len; /* 0 (don't know), 6 or 10 */
|
||||
uint8_t raw_curr[SCSI_IECMP_RAW_LEN];
|
||||
uint8_t raw_chg[SCSI_IECMP_RAW_LEN];
|
||||
};
|
||||
|
||||
/* Carrier for Error counter log pages (e.g. read, write, verify ...) */
|
||||
struct scsiErrorCounter
|
||||
{
|
||||
uint8_t gotPC[7];
|
||||
uint8_t gotExtraPC;
|
||||
uint64_t counter[8];
|
||||
};
|
||||
|
||||
/* Carrier for Non-medium error log page */
|
||||
struct scsiNonMediumError
|
||||
{
|
||||
uint8_t gotPC0;
|
||||
uint8_t gotExtraPC;
|
||||
uint64_t counterPC0;
|
||||
uint8_t gotTFE_H;
|
||||
uint64_t counterTFE_H; /* Track following errors [Hitachi] */
|
||||
uint8_t gotPE_H;
|
||||
uint64_t counterPE_H; /* Positioning errors [Hitachi] */
|
||||
};
|
||||
|
||||
struct scsi_readcap_resp
|
||||
{
|
||||
uint64_t num_lblocks; /* Number of Logical Blocks on device */
|
||||
uint32_t lb_size; /* should be available in all non-error cases */
|
||||
/* following fields from READ CAPACITY(16) or set to 0 */
|
||||
uint8_t prot_type; /* 0, 1, 2 or 3 protection type, deduced from
|
||||
* READ CAPACITY(16) P_TYPE and PROT_EN fields */
|
||||
uint8_t p_i_exp; /* Protection information Intervals Exponent */
|
||||
uint8_t lb_p_pb_exp; /* Logical Blocks per Physical Block Exponent */
|
||||
bool lbpme; /* Logical Block Provisioning Management Enabled */
|
||||
bool lbprz; /* Logical Block Provisioning Read Zeros */
|
||||
uint16_t l_a_lba; /* Lowest Aligned Logical Block Address */
|
||||
};
|
||||
|
||||
struct scsi_supp_log_pages
|
||||
{
|
||||
uint8_t page_code;
|
||||
uint8_t subpage_code;
|
||||
};
|
||||
|
||||
/* SCSI Peripheral types (of interest) */
|
||||
#define SCSI_PT_DIRECT_ACCESS 0x0
|
||||
#define SCSI_PT_SEQUENTIAL_ACCESS 0x1
|
||||
#define SCSI_PT_CDROM 0x5
|
||||
#define SCSI_PT_MEDIUM_CHANGER 0x8
|
||||
#define SCSI_PT_ENCLOSURE 0xd
|
||||
#define SCSI_PT_HOST_MANAGED 0x14 /* Zoned disk */
|
||||
|
||||
/* Transport protocol identifiers or just Protocol identifiers */
|
||||
#define SCSI_TPROTO_FCP 0
|
||||
#define SCSI_TPROTO_SPI 1
|
||||
#define SCSI_TPROTO_SSA 2
|
||||
#define SCSI_TPROTO_1394 3
|
||||
#define SCSI_TPROTO_SRP 4 /* SCSI over RDMA */
|
||||
#define SCSI_TPROTO_ISCSI 5
|
||||
#define SCSI_TPROTO_SAS 6
|
||||
#define SCSI_TPROTO_ADT 7
|
||||
#define SCSI_TPROTO_ATA 8
|
||||
#define SCSI_TPROTO_UAS 9 /* USB attached SCSI */
|
||||
#define SCSI_TPROTO_SOP 0xa /* SCSI over PCIe */
|
||||
#define SCSI_TPROTO_PCIE 0xb /* includes NVMe */
|
||||
#define SCSI_TPROTO_NONE 0xf
|
||||
|
||||
/* SCSI Log Pages retrieved by LOG SENSE. 0x0 to 0x3f, 0x30 to 0x3e vendor */
|
||||
#define SUPPORTED_LPAGES 0x00
|
||||
#define BUFFER_OVERRUN_LPAGE 0x01
|
||||
#define WRITE_ERROR_COUNTER_LPAGE 0x02
|
||||
#define READ_ERROR_COUNTER_LPAGE 0x03
|
||||
#define READ_REVERSE_ERROR_COUNTER_LPAGE 0x04
|
||||
#define VERIFY_ERROR_COUNTER_LPAGE 0x05
|
||||
#define NON_MEDIUM_ERROR_LPAGE 0x06
|
||||
#define LAST_N_ERROR_EVENTS_LPAGE 0x07
|
||||
#define FORMAT_STATUS_LPAGE 0x08
|
||||
#define LAST_N_DEFERRED_LPAGE 0x0b /* or async events */
|
||||
#define LB_PROV_LPAGE 0x0c /* SBC-3 */
|
||||
#define TEMPERATURE_LPAGE 0x0d
|
||||
#define STARTSTOP_CYCLE_COUNTER_LPAGE 0x0e
|
||||
#define APPLICATION_CLIENT_LPAGE 0x0f
|
||||
#define SELFTEST_RESULTS_LPAGE 0x10
|
||||
#define SS_MEDIA_LPAGE 0x11 /* SBC-3 */
|
||||
#define DEVICE_STATS_LPAGE 0x14 /* SSC-5 */
|
||||
#define BACKGROUND_RESULTS_LPAGE 0x15 /* SBC-3 */
|
||||
#define ATA_PT_RESULTS_LPAGE 0x16 /* SAT */
|
||||
#define NONVOL_CACHE_LPAGE 0x17 /* SBC-3 */
|
||||
#define PROTOCOL_SPECIFIC_LPAGE 0x18
|
||||
#define GEN_STATS_PERF_LPAGE 0x19
|
||||
#define POWER_COND_TRANS_LPAGE 0x1a
|
||||
#define IE_LPAGE 0x2f
|
||||
|
||||
/* SCSI Log subpages (8 bits), added spc4r05 2006, standardized SPC-4 2015 */
|
||||
#define NO_SUBPAGE_L_SPAGE 0x0 /* 0x0-0x3f,0x0 */
|
||||
#define LAST_N_INQ_DAT_L_SPAGE 0x1 /* 0xb,0x1 */
|
||||
#define LAST_N_MODE_PG_L_SPAGE 0x2 /* 0xb,0x2 */
|
||||
#define ENVIRO_REP_L_SPAGE 0x1 /* 0xd,0x1 */
|
||||
#define ENVIRO_LIMITS_L_SPAGE 0x2 /* 0xd,0x2 */
|
||||
#define UTILIZATION_L_SPAGE 0x1 /* 0xe,0x1 */
|
||||
#define ZB_DEV_STATS_L_SPAGE 0x1 /* 0x14,0x1 */
|
||||
#define PEND_DEFECTS_L_SPAGE 0x1 /* 0x15,0x1 */
|
||||
#define BACKGROUND_OP_L_SPAGE 0x2 /* 0x15,0x2 */
|
||||
#define LPS_MISALIGN_L_SPAGE 0x3 /* 0x15,0x3 */
|
||||
#define SUPP_SPAGE_L_SPAGE 0xff /* 0x0,0xff pages+subpages */
|
||||
|
||||
/* Seagate vendor specific log pages. */
|
||||
#define SEAGATE_CACHE_LPAGE 0x37
|
||||
#define SEAGATE_FACTORY_LPAGE 0x3e
|
||||
|
||||
/* Log page response lengths */
|
||||
#define LOG_RESP_SELF_TEST_LEN 0x194
|
||||
|
||||
/* See the SSC-2 document at www.t10.org . Earlier note: From IBM
|
||||
Documentation, see http://www.storage.ibm.com/techsup/hddtech/prodspecs.htm */
|
||||
#define TAPE_ALERTS_LPAGE 0x2e
|
||||
|
||||
/* ANSI SCSI-3 Mode Pages */
|
||||
#define VENDOR_UNIQUE_PAGE 0x00
|
||||
#define READ_WRITE_ERROR_RECOVERY_PAGE 0x01
|
||||
#define DISCONNECT_RECONNECT_PAGE 0x02
|
||||
#define FORMAT_DEVICE_PAGE 0x03
|
||||
#define RIGID_DISK_DRIVE_GEOMETRY_PAGE 0x04
|
||||
#define FLEXIBLE_DISK_PAGE 0x05
|
||||
#define VERIFY_ERROR_RECOVERY_PAGE 0x07
|
||||
#define CACHING_PAGE 0x08
|
||||
#define PERIPHERAL_DEVICE_PAGE 0x09
|
||||
#define XOR_CONTROL_MODE_PAGE 0x10
|
||||
#define CONTROL_MODE_PAGE 0x0a
|
||||
#define MEDIUM_TYPES_SUPPORTED_PAGE 0x0b
|
||||
#define NOTCH_PAGE 0x0c
|
||||
#define CD_DEVICE_PAGE 0x0d
|
||||
#define CD_AUDIO_CONTROL_PAGE 0x0e
|
||||
#define DATA_COMPRESSION_PAGE 0x0f
|
||||
#define ENCLOSURE_SERVICES_MANAGEMENT_PAGE 0x14
|
||||
#define PROTOCOL_SPECIFIC_LUN_PAGE 0x18
|
||||
#define PROTOCOL_SPECIFIC_PORT_PAGE 0x19
|
||||
#define POWER_CONDITION_PAGE 0x1a
|
||||
#define INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE 0x1c
|
||||
#define FAULT_FAILURE_REPORTING_PAGE 0x1c
|
||||
|
||||
/* Background control mode subpage is [0x1c,0x1] */
|
||||
#define BACKGROUND_CONTROL_M_SUBPAGE 0x1 /* SBC-2 */
|
||||
|
||||
#define ALL_MODE_PAGES 0x3f
|
||||
|
||||
/* Mode page control field */
|
||||
#define MPAGE_CONTROL_CURRENT 0
|
||||
#define MPAGE_CONTROL_CHANGEABLE 1
|
||||
#define MPAGE_CONTROL_DEFAULT 2
|
||||
#define MPAGE_CONTROL_SAVED 3
|
||||
|
||||
/* SCSI Vital Product Data (VPD) pages */
|
||||
#define SCSI_VPD_SUPPORTED_VPD_PAGES 0x0
|
||||
#define SCSI_VPD_UNIT_SERIAL_NUMBER 0x80
|
||||
#define SCSI_VPD_DEVICE_IDENTIFICATION 0x83
|
||||
#define SCSI_VPD_EXTENDED_INQUIRY_DATA 0x86
|
||||
#define SCSI_VPD_ATA_INFORMATION 0x89
|
||||
#define SCSI_VPD_POWER_CONDITION 0x8a
|
||||
#define SCSI_VPD_POWER_CONSUMPTION 0x8d
|
||||
#define SCSI_VPD_BLOCK_LIMITS 0xb0
|
||||
#define SCSI_VPD_BLOCK_DEVICE_CHARACTERISTICS 0xb1
|
||||
#define SCSI_VPD_LOGICAL_BLOCK_PROVISIONING 0xb2
|
||||
#define SCSI_VPD_ZONED_BLOCK_DEV_CHAR 0xb6
|
||||
|
||||
/* defines for useful SCSI Status codes */
|
||||
#define SCSI_STATUS_CHECK_CONDITION 0x2
|
||||
|
||||
/* defines for useful Sense Key codes */
|
||||
#define SCSI_SK_NO_SENSE 0x0
|
||||
#define SCSI_SK_RECOVERED_ERR 0x1
|
||||
#define SCSI_SK_NOT_READY 0x2
|
||||
#define SCSI_SK_MEDIUM_ERROR 0x3
|
||||
#define SCSI_SK_HARDWARE_ERROR 0x4
|
||||
#define SCSI_SK_ILLEGAL_REQUEST 0x5
|
||||
#define SCSI_SK_UNIT_ATTENTION 0x6
|
||||
#define SCSI_SK_DATA_PROTECT 0x7
|
||||
#define SCSI_SK_ABORTED_COMMAND 0xb
|
||||
#define SCSI_SK_MISCOMPARE 0xe
|
||||
#define SCSI_SK_COMPLETED 0xf
|
||||
|
||||
/* defines for useful Additional Sense Codes (ASCs) */
|
||||
#define SCSI_ASC_NOT_READY 0x4 /* more info in ASCQ code */
|
||||
#define SCSI_ASC_NO_MEDIUM 0x3a /* more info in ASCQ code */
|
||||
#define SCSI_ASC_UNKNOWN_OPCODE 0x20
|
||||
#define SCSI_ASC_INVALID_FIELD 0x24
|
||||
#define SCSI_ASC_UNKNOWN_PARAM 0x26
|
||||
#define SCSI_ASC_WARNING 0xb
|
||||
#define SCSI_ASC_IMPENDING_FAILURE 0x5d
|
||||
|
||||
#define SCSI_ASCQ_ATA_PASS_THROUGH 0x1d
|
||||
|
||||
/* Simplified error code (negative values as per errno) */
|
||||
#define SIMPLE_NO_ERROR 0
|
||||
#define SIMPLE_ERR_NOT_READY 1
|
||||
#define SIMPLE_ERR_BAD_OPCODE 2
|
||||
#define SIMPLE_ERR_BAD_FIELD 3 /* in cbd */
|
||||
#define SIMPLE_ERR_BAD_PARAM 4 /* in data */
|
||||
#define SIMPLE_ERR_BAD_RESP 5 /* response fails sanity */
|
||||
#define SIMPLE_ERR_NO_MEDIUM 6 /* no medium present */
|
||||
#define SIMPLE_ERR_BECOMING_READY 7 /* device will be ready soon */
|
||||
#define SIMPLE_ERR_TRY_AGAIN 8 /* some warning, try again */
|
||||
#define SIMPLE_ERR_MEDIUM_HARDWARE 9 /* medium or hardware error */
|
||||
#define SIMPLE_ERR_UNKNOWN 10 /* unknown sense value */
|
||||
#define SIMPLE_ERR_ABORTED_COMMAND 11 /* probably transport error */
|
||||
#define SIMPLE_ERR_PROTECTION 12 /* data protect sense key */
|
||||
#define SIMPLE_ERR_MISCOMPARE 13 /* from VERIFY commands */
|
||||
|
||||
/* defines for functioncode parameter in SENDDIAGNOSTIC function */
|
||||
#define SCSI_DIAG_NO_SELF_TEST 0x00
|
||||
#define SCSI_DIAG_DEF_SELF_TEST 0xff
|
||||
#define SCSI_DIAG_BG_SHORT_SELF_TEST 0x01
|
||||
#define SCSI_DIAG_BG_EXTENDED_SELF_TEST 0x02
|
||||
#define SCSI_DIAG_FG_SHORT_SELF_TEST 0x05
|
||||
#define SCSI_DIAG_FG_EXTENDED_SELF_TEST 0x06
|
||||
#define SCSI_DIAG_ABORT_SELF_TEST 0x04
|
||||
|
||||
/* Defines for power_cond in scsiSetPowerCondition() (SSU command) */
|
||||
#define SCSI_POW_COND_ACTIVE 0x1
|
||||
#define SCSI_POW_COND_IDLE 0x2
|
||||
#define SCSI_POW_COND_STANDBY 0x3
|
||||
|
||||
/* SCSI command timeout values (units are seconds) */
|
||||
#define SCSI_TIMEOUT_DEFAULT 60 // should be longer than the spin up time
|
||||
// of a disk in JBOD.
|
||||
|
||||
#define SCSI_TIMEOUT_SELF_TEST (5 * 60 * 60) /* allow max 5 hours for */
|
||||
/* extended foreground self test */
|
||||
|
||||
#define LOGPAGEHDRSIZE 4
|
||||
|
||||
class scsi_device;
|
||||
|
||||
// Set of supported SCSI VPD pages. Constructor fetches Supported VPD pages
|
||||
// VPD page and remembers the response for later queries.
|
||||
class supported_vpd_pages
|
||||
{
|
||||
public:
|
||||
explicit supported_vpd_pages(scsi_device *device);
|
||||
|
||||
bool is_supported(int vpd_page_num) const;
|
||||
|
||||
private:
|
||||
int num_valid; /* 0 or less for invalid */
|
||||
unsigned char pages[256];
|
||||
};
|
||||
|
||||
extern supported_vpd_pages *supported_vpd_pages_p;
|
||||
|
||||
/* This is a heuristic that takes into account the command bytes and length
|
||||
* to decide whether the presented unstructured sequence of bytes could be
|
||||
* a SCSI command. If so it returns true otherwise false. Vendor specific
|
||||
* SCSI commands (i.e. opcodes from 0xc0 to 0xff), if presented, are assumed
|
||||
* to follow SCSI conventions (i.e. length of 6, 10, 12 or 16 bytes). The
|
||||
* only SCSI commands considered above 16 bytes of length are the Variable
|
||||
* Length Commands (opcode 0x7f) and the XCDB wrapped commands (opcode 0x7e).
|
||||
* Both have an inbuilt length field which can be cross checked with clen.
|
||||
* No NVMe commands (64 bytes long plus some extra added by some OSes) have
|
||||
* opcodes 0x7e or 0x7f yet. ATA is register based but SATA has FIS
|
||||
* structures that are sent across the wire. The FIS register structure is
|
||||
* used to move a command from a SATA host to device, but the ATA 'command'
|
||||
* is not the first byte. So it is harder to say what will happen if a
|
||||
* FIS structure is presented as a SCSI command, hopefully there is a low
|
||||
* probability this function will yield true in that case. */
|
||||
bool is_scsi_cdb(const uint8_t *cdbp, int clen);
|
||||
|
||||
// Print SCSI debug messages?
|
||||
extern unsigned char scsi_debugmode;
|
||||
|
||||
void scsi_do_sense_disect(const struct scsi_cmnd_io *in,
|
||||
struct scsi_sense_disect *out);
|
||||
|
||||
int scsiSimpleSenseFilter(const struct scsi_sense_disect *sinfo);
|
||||
|
||||
const char *scsiErrString(int scsiErr);
|
||||
|
||||
/* Yield string associated with sense_key value. Returns 'buff'. */
|
||||
char *scsi_get_sense_key_str(int sense_key, int buff_len, char *buff);
|
||||
|
||||
int scsi_vpd_dev_id_iter(const unsigned char *initial_desig_desc,
|
||||
int page_len, int *off, int m_assoc,
|
||||
int m_desig_type, int m_code_set);
|
||||
|
||||
int scsi_decode_lu_dev_id(const unsigned char *b, int blen, char *s,
|
||||
int slen, int *transport);
|
||||
|
||||
/* STANDARD SCSI Commands */
|
||||
int scsiTestUnitReady(scsi_device *device);
|
||||
|
||||
int scsiStdInquiry(scsi_device *device, uint8_t *pBuf, int bufLen);
|
||||
|
||||
int scsiInquiryVpd(scsi_device *device, int vpd_page, uint8_t *pBuf,
|
||||
int bufLen);
|
||||
|
||||
int scsiLogSense(scsi_device *device, int pagenum, int subpagenum,
|
||||
uint8_t *pBuf, int bufLen, int known_resp_len);
|
||||
|
||||
int scsiLogSelect(scsi_device *device, int pcr, int sp, int pc, int pagenum,
|
||||
int subpagenum, uint8_t *pBuf, int bufLen);
|
||||
|
||||
int scsiModeSense(scsi_device *device, int pagenum, int subpagenum, int pc,
|
||||
uint8_t *pBuf, int bufLen);
|
||||
|
||||
int scsiModeSelect(scsi_device *device, int sp, uint8_t *pBuf, int bufLen);
|
||||
|
||||
int scsiModeSense10(scsi_device *device, int pagenum, int subpagenum, int pc,
|
||||
uint8_t *pBuf, int bufLen);
|
||||
|
||||
int scsiModeSelect10(scsi_device *device, int sp, uint8_t *pBuf, int bufLen);
|
||||
|
||||
int scsiModePageOffset(const uint8_t *resp, int len, int modese_len);
|
||||
|
||||
int scsiRequestSense(scsi_device *device,
|
||||
struct scsi_sense_disect *sense_info);
|
||||
|
||||
int scsiSetPowerCondition(scsi_device *device, int power_cond,
|
||||
int pcond_modifier = 0);
|
||||
|
||||
int scsiSendDiagnostic(scsi_device *device, int functioncode, uint8_t *pBuf,
|
||||
int bufLen);
|
||||
|
||||
bool scsi_pass_through_yield_sense(scsi_device *device, scsi_cmnd_io *iop,
|
||||
struct scsi_sense_disect &sinfo);
|
||||
|
||||
int scsiReadDefect10(scsi_device *device, int req_plist, int req_glist,
|
||||
int dl_format, uint8_t *pBuf, int bufLen);
|
||||
|
||||
int scsiReadDefect12(scsi_device *device, int req_plist, int req_glist,
|
||||
int dl_format, int addrDescIndex, uint8_t *pBuf,
|
||||
int bufLen);
|
||||
|
||||
int scsiReadCapacity10(scsi_device *device, unsigned int *last_lbp,
|
||||
unsigned int *lb_sizep);
|
||||
|
||||
int scsiReadCapacity16(scsi_device *device, uint8_t *pBuf, int bufLen);
|
||||
|
||||
/* SMART specific commands */
|
||||
int scsiCheckIE(scsi_device *device, int hasIELogPage, int hasTempLogPage,
|
||||
uint8_t *asc, uint8_t *ascq, uint8_t *currenttemp,
|
||||
uint8_t *triptemp);
|
||||
|
||||
int scsiFetchIECmpage(scsi_device *device, struct scsi_iec_mode_page *iecp,
|
||||
int modese_len);
|
||||
int scsi_IsExceptionControlEnabled(const struct scsi_iec_mode_page *iecp);
|
||||
int scsi_IsWarningEnabled(const struct scsi_iec_mode_page *iecp);
|
||||
int scsiSetExceptionControlAndWarning(scsi_device *device, int enabled,
|
||||
const struct scsi_iec_mode_page *iecp);
|
||||
void scsiDecodeErrCounterPage(unsigned char *resp,
|
||||
struct scsiErrorCounter *ecp);
|
||||
void scsiDecodeNonMediumErrPage(unsigned char *resp,
|
||||
struct scsiNonMediumError *nmep);
|
||||
int scsiFetchExtendedSelfTestTime(scsi_device *device, int *durationSec,
|
||||
int modese_len);
|
||||
int scsiCountFailedSelfTests(scsi_device *device, int noisy);
|
||||
int scsiSelfTestInProgress(scsi_device *device, int *inProgress);
|
||||
int scsiFetchControlGLTSD(scsi_device *device, int modese_len, int current);
|
||||
int scsiSetControlGLTSD(scsi_device *device, int enabled, int modese_len);
|
||||
int scsiFetchTransportProtocol(scsi_device *device, int modese_len);
|
||||
int scsiGetRPM(scsi_device *device, int modese_len, int *form_factorp,
|
||||
int *haw_zbcp);
|
||||
int scsiGetSetCache(scsi_device *device, int modese_len, short int *wce,
|
||||
short int *rcd);
|
||||
uint64_t scsiGetSize(scsi_device *device, bool avoid_rcap16,
|
||||
struct scsi_readcap_resp *srrp);
|
||||
|
||||
/* T10 Standard IE Additional Sense Code strings taken from t10.org */
|
||||
const char *scsiGetIEString(uint8_t asc, uint8_t ascq);
|
||||
int scsiGetTemp(scsi_device *device, uint8_t *currenttemp, uint8_t *triptemp);
|
||||
|
||||
int scsiSmartDefaultSelfTest(scsi_device *device);
|
||||
int scsiSmartShortSelfTest(scsi_device *device);
|
||||
int scsiSmartExtendSelfTest(scsi_device *device);
|
||||
int scsiSmartShortCapSelfTest(scsi_device *device);
|
||||
int scsiSmartExtendCapSelfTest(scsi_device *device);
|
||||
int scsiSmartSelfTestAbort(scsi_device *device);
|
||||
|
||||
const char *scsiTapeAlertsTapeDevice(unsigned short code);
|
||||
const char *scsiTapeAlertsChangerDevice(unsigned short code);
|
||||
|
||||
const char *scsi_get_opcode_name(uint8_t opcode);
|
||||
void scsi_format_id_string(char *out, const uint8_t *in, int n);
|
||||
|
||||
void dStrHex(const uint8_t *up, int len, int no_ascii);
|
||||
|
||||
/* Attempt to find the first SCSI sense data descriptor that matches the
|
||||
given 'desc_type'. If found return pointer to start of sense data
|
||||
descriptor; otherwise (including fixed format sense data) returns NULL. */
|
||||
const unsigned char *sg_scsi_sense_desc_find(const unsigned char *sensep,
|
||||
int sense_len, int desc_type);
|
||||
|
||||
/* SCSI command transmission interface function declaration. Its
|
||||
* definition is target OS specific (see os_<OS>.c file).
|
||||
* Returns 0 if SCSI command successfully launched and response
|
||||
* received. Even when 0 is returned the caller should check
|
||||
* scsi_cmnd_io::scsi_status for SCSI defined errors and warnings
|
||||
* (e.g. CHECK CONDITION). If the SCSI command could not be issued
|
||||
* (e.g. device not present or not a SCSI device) or some other problem
|
||||
* arises (e.g. timeout) then returns a negative errno value. */
|
||||
// Moved to C++ interface
|
||||
// int do_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report);
|
||||
|
||||
#endif
|
|
@ -1,459 +0,0 @@
|
|||
/*
|
||||
* scsinvme.cpp
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2020-21 Christian Franke
|
||||
* Copyright (C) 2018 Harry Mallon <hjmallon@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "dev_interface.h"
|
||||
#include "dev_tunnelled.h"
|
||||
#include "nvmecmds.h"
|
||||
#include "scsicmds.h"
|
||||
#include "sg_unaligned.h"
|
||||
#include "utility.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
const char *scsinvme_cpp_svnid = "$Id: scsinvme.cpp 5337 2022-02-27 07:53:55Z dpgilbert $";
|
||||
|
||||
// SNT (SCSI NVMe Translation) namespace and prefix
|
||||
namespace snt
|
||||
{
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// sntasmedia_device
|
||||
|
||||
class sntasmedia_device
|
||||
: public tunnelled_device<
|
||||
/*implements*/ nvme_device,
|
||||
/*by tunnelling through a*/ scsi_device>
|
||||
{
|
||||
public:
|
||||
sntasmedia_device(smart_interface *intf, scsi_device *scsidev,
|
||||
const char *req_type, unsigned nsid);
|
||||
|
||||
virtual ~sntasmedia_device();
|
||||
|
||||
virtual bool nvme_pass_through(const nvme_cmd_in &in, nvme_cmd_out &out) override;
|
||||
};
|
||||
|
||||
sntasmedia_device::sntasmedia_device(smart_interface *intf, scsi_device *scsidev,
|
||||
const char *req_type, unsigned nsid)
|
||||
: smart_device(intf, scsidev->get_dev_name(), "sntasmedia", req_type),
|
||||
tunnelled_device<nvme_device, scsi_device>(scsidev, nsid)
|
||||
{
|
||||
set_info().info_name = strprintf("%s [USB NVMe ASMedia]", scsidev->get_info_name());
|
||||
}
|
||||
|
||||
sntasmedia_device::~sntasmedia_device()
|
||||
{
|
||||
}
|
||||
|
||||
bool sntasmedia_device::nvme_pass_through(const nvme_cmd_in &in, nvme_cmd_out & /* out */)
|
||||
{
|
||||
unsigned size = in.size;
|
||||
unsigned cdw10_hi = in.cdw10 >> 16;
|
||||
switch (in.opcode)
|
||||
{
|
||||
case smartmontools::nvme_admin_identify:
|
||||
if (in.cdw10 == 0x0000001) // Identify controller
|
||||
break;
|
||||
if (in.cdw10 == 0x0000000)
|
||||
{ // Identify namespace
|
||||
if (in.nsid == 1)
|
||||
break;
|
||||
return set_err(ENOSYS, "NVMe Identify Namespace 0x%x not supported", in.nsid);
|
||||
}
|
||||
return set_err(ENOSYS, "NVMe Identify with CDW10=0x%08x not supported", in.cdw10);
|
||||
case smartmontools::nvme_admin_get_log_page:
|
||||
if (!(in.nsid == 0xffffffff || !in.nsid))
|
||||
return set_err(ENOSYS, "NVMe Get Log Page with NSID=0x%x not supported", in.nsid);
|
||||
if (size > 0x200)
|
||||
{ // Reading more results in command timeout
|
||||
// TODO: Add ability to return short reads to caller
|
||||
size = 0x200;
|
||||
cdw10_hi = (size / 4) - 1;
|
||||
pout("Warning: NVMe Get Log truncated to 0x%03x bytes, 0x%03x bytes zero filled\n", size, in.size - size);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return set_err(ENOSYS, "NVMe admin command 0x%02x not supported", in.opcode);
|
||||
break;
|
||||
}
|
||||
if (in.cdw11 || in.cdw12 || in.cdw13 || in.cdw14 || in.cdw15)
|
||||
return set_err(ENOSYS, "Nonzero NVMe command dwords 11-15 not supported");
|
||||
|
||||
uint8_t cdb[16] = {
|
||||
0,
|
||||
};
|
||||
cdb[0] = 0xe6;
|
||||
cdb[1] = in.opcode;
|
||||
// cdb[2] = ?
|
||||
cdb[3] = (uint8_t)in.cdw10;
|
||||
// cdb[4..6] = ?
|
||||
cdb[7] = (uint8_t)cdw10_hi;
|
||||
// cdb[8..15] = ?
|
||||
|
||||
scsi_cmnd_io io_hdr = {};
|
||||
io_hdr.cmnd = cdb;
|
||||
io_hdr.cmnd_len = sizeof(cdb);
|
||||
io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
|
||||
io_hdr.dxferp = (uint8_t *)in.buffer;
|
||||
io_hdr.dxfer_len = size;
|
||||
memset(in.buffer, 0, in.size);
|
||||
|
||||
scsi_device *scsidev = get_tunnel_dev();
|
||||
if (!scsidev->scsi_pass_through_and_check(&io_hdr, "sntasmedia_device::nvme_pass_through: "))
|
||||
return set_err(scsidev->get_err());
|
||||
|
||||
// out.result = ?;
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// sntjmicron_device
|
||||
|
||||
#define SNT_JMICRON_NVME_SIGNATURE 0x454d564eu // 'NVME' reversed (little endian)
|
||||
#define SNT_JMICRON_CDB_LEN 12
|
||||
#define SNT_JMICRON_NVM_CMD_LEN 512
|
||||
|
||||
class sntjmicron_device
|
||||
: public tunnelled_device<
|
||||
/*implements*/ nvme_device,
|
||||
/*by tunnelling through a*/ scsi_device>
|
||||
{
|
||||
public:
|
||||
sntjmicron_device(smart_interface *intf, scsi_device *scsidev,
|
||||
const char *req_type, unsigned nsid);
|
||||
|
||||
virtual ~sntjmicron_device();
|
||||
|
||||
virtual bool open() override;
|
||||
|
||||
virtual bool nvme_pass_through(const nvme_cmd_in &in, nvme_cmd_out &out) override;
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
proto_nvm_cmd = 0x0,
|
||||
proto_non_data = 0x1,
|
||||
proto_dma_in = 0x2,
|
||||
proto_dma_out = 0x3,
|
||||
proto_response = 0xF
|
||||
};
|
||||
};
|
||||
|
||||
sntjmicron_device::sntjmicron_device(smart_interface *intf, scsi_device *scsidev,
|
||||
const char *req_type, unsigned nsid)
|
||||
: smart_device(intf, scsidev->get_dev_name(), "sntjmicron", req_type),
|
||||
tunnelled_device<nvme_device, scsi_device>(scsidev, nsid)
|
||||
{
|
||||
set_info().info_name = strprintf("%s [USB NVMe JMicron]", scsidev->get_info_name());
|
||||
}
|
||||
|
||||
sntjmicron_device::~sntjmicron_device()
|
||||
{
|
||||
}
|
||||
|
||||
bool sntjmicron_device::open()
|
||||
{
|
||||
// Open USB first
|
||||
if (!tunnelled_device<nvme_device, scsi_device>::open())
|
||||
return false;
|
||||
|
||||
// No sure how multiple namespaces come up on device so we
|
||||
// cannot detect e.g. /dev/sdX is NSID 2.
|
||||
// Set to broadcast if not available
|
||||
if (!get_nsid())
|
||||
{
|
||||
set_nsid(0xFFFFFFFF);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// cdb[0]: ATA PASS THROUGH (12) SCSI command opcode byte (0xa1)
|
||||
// cdb[1]: [ is admin cmd: 1 ] [ protocol : 7 ]
|
||||
// cdb[2]: reserved
|
||||
// cdb[3]: parameter list length (23:16)
|
||||
// cdb[4]: parameter list length (15:08)
|
||||
// cdb[5]: parameter list length (07:00)
|
||||
// cdb[6]: reserved
|
||||
// cdb[7]: reserved
|
||||
// cdb[8]: reserved
|
||||
// cdb[9]: reserved
|
||||
// cdb[10]: reserved
|
||||
// cdb[11]: CONTROL (?)
|
||||
bool sntjmicron_device::nvme_pass_through(const nvme_cmd_in &in, nvme_cmd_out &out)
|
||||
{
|
||||
/* Only admin commands used */
|
||||
constexpr bool admin = true;
|
||||
|
||||
// 1: "NVM Command Set Payload"
|
||||
{
|
||||
unsigned char cdb[SNT_JMICRON_CDB_LEN] = {0};
|
||||
cdb[0] = SAT_ATA_PASSTHROUGH_12;
|
||||
cdb[1] = (admin ? 0x80 : 0x00) | proto_nvm_cmd;
|
||||
sg_put_unaligned_be24(SNT_JMICRON_NVM_CMD_LEN, &cdb[3]);
|
||||
|
||||
unsigned nvm_cmd[SNT_JMICRON_NVM_CMD_LEN / sizeof(unsigned)] = {0};
|
||||
nvm_cmd[0] = SNT_JMICRON_NVME_SIGNATURE;
|
||||
// nvm_cmd[1]: reserved
|
||||
nvm_cmd[2] = in.opcode; // More of CDW0 may go in here in future
|
||||
nvm_cmd[3] = in.nsid;
|
||||
// nvm_cmd[4-5]: reserved
|
||||
// nvm_cmd[6-7]: metadata pointer
|
||||
// nvm_cmd[8-11]: data ptr (?)
|
||||
nvm_cmd[12] = in.cdw10;
|
||||
nvm_cmd[13] = in.cdw11;
|
||||
nvm_cmd[14] = in.cdw12;
|
||||
nvm_cmd[15] = in.cdw13;
|
||||
nvm_cmd[16] = in.cdw14;
|
||||
nvm_cmd[17] = in.cdw15;
|
||||
// nvm_cmd[18-127]: reserved
|
||||
|
||||
if (isbigendian())
|
||||
for (unsigned i = 0; i < (SNT_JMICRON_NVM_CMD_LEN / sizeof(uint32_t)); i++)
|
||||
swapx(&nvm_cmd[i]);
|
||||
|
||||
scsi_cmnd_io io_nvm = {};
|
||||
|
||||
io_nvm.cmnd = cdb;
|
||||
io_nvm.cmnd_len = SNT_JMICRON_CDB_LEN;
|
||||
io_nvm.dxfer_dir = DXFER_TO_DEVICE;
|
||||
io_nvm.dxferp = (uint8_t *)nvm_cmd;
|
||||
io_nvm.dxfer_len = SNT_JMICRON_NVM_CMD_LEN;
|
||||
|
||||
scsi_device *scsidev = get_tunnel_dev();
|
||||
if (!scsidev->scsi_pass_through_and_check(&io_nvm,
|
||||
"sntjmicron_device::nvme_pass_through:NVM: "))
|
||||
return set_err(scsidev->get_err());
|
||||
}
|
||||
|
||||
// 2: DMA or Non-Data
|
||||
{
|
||||
unsigned char cdb[SNT_JMICRON_CDB_LEN] = {0};
|
||||
cdb[0] = SAT_ATA_PASSTHROUGH_12;
|
||||
|
||||
scsi_cmnd_io io_data = {};
|
||||
io_data.cmnd = cdb;
|
||||
io_data.cmnd_len = SNT_JMICRON_CDB_LEN;
|
||||
|
||||
switch (in.direction())
|
||||
{
|
||||
case nvme_cmd_in::no_data:
|
||||
cdb[1] = (admin ? 0x80 : 0x00) | proto_non_data;
|
||||
io_data.dxfer_dir = DXFER_NONE;
|
||||
break;
|
||||
case nvme_cmd_in::data_out:
|
||||
cdb[1] = (admin ? 0x80 : 0x00) | proto_dma_out;
|
||||
sg_put_unaligned_be24(in.size, &cdb[3]);
|
||||
io_data.dxfer_dir = DXFER_TO_DEVICE;
|
||||
io_data.dxferp = (uint8_t *)in.buffer;
|
||||
io_data.dxfer_len = in.size;
|
||||
break;
|
||||
case nvme_cmd_in::data_in:
|
||||
cdb[1] = (admin ? 0x80 : 0x00) | proto_dma_in;
|
||||
sg_put_unaligned_be24(in.size, &cdb[3]);
|
||||
io_data.dxfer_dir = DXFER_FROM_DEVICE;
|
||||
io_data.dxferp = (uint8_t *)in.buffer;
|
||||
io_data.dxfer_len = in.size;
|
||||
memset(in.buffer, 0, in.size);
|
||||
break;
|
||||
case nvme_cmd_in::data_io:
|
||||
default:
|
||||
return set_err(EINVAL);
|
||||
}
|
||||
|
||||
scsi_device *scsidev = get_tunnel_dev();
|
||||
if (!scsidev->scsi_pass_through_and_check(&io_data,
|
||||
"sntjmicron_device::nvme_pass_through:Data: "))
|
||||
return set_err(scsidev->get_err());
|
||||
}
|
||||
|
||||
// 3: "Return Response Information"
|
||||
{
|
||||
unsigned char cdb[SNT_JMICRON_CDB_LEN] = {0};
|
||||
cdb[0] = SAT_ATA_PASSTHROUGH_12;
|
||||
cdb[1] = (admin ? 0x80 : 0x00) | proto_response;
|
||||
sg_put_unaligned_be24(SNT_JMICRON_NVM_CMD_LEN, &cdb[3]);
|
||||
|
||||
unsigned nvm_reply[SNT_JMICRON_NVM_CMD_LEN / sizeof(unsigned)] = {0};
|
||||
|
||||
scsi_cmnd_io io_reply = {};
|
||||
|
||||
io_reply.cmnd = cdb;
|
||||
io_reply.cmnd_len = SNT_JMICRON_CDB_LEN;
|
||||
io_reply.dxfer_dir = DXFER_FROM_DEVICE;
|
||||
io_reply.dxferp = (uint8_t *)nvm_reply;
|
||||
io_reply.dxfer_len = SNT_JMICRON_NVM_CMD_LEN;
|
||||
|
||||
scsi_device *scsidev = get_tunnel_dev();
|
||||
if (!scsidev->scsi_pass_through_and_check(&io_reply,
|
||||
"sntjmicron_device::nvme_pass_through:Reply: "))
|
||||
return set_err(scsidev->get_err());
|
||||
|
||||
if (isbigendian())
|
||||
for (unsigned i = 0; i < (SNT_JMICRON_NVM_CMD_LEN / sizeof(uint32_t)); i++)
|
||||
swapx(&nvm_reply[i]);
|
||||
|
||||
if (nvm_reply[0] != SNT_JMICRON_NVME_SIGNATURE)
|
||||
return set_err(EIO, "Out of spec JMicron NVMe reply");
|
||||
|
||||
int status = nvm_reply[5] >> 17;
|
||||
|
||||
if (status > 0)
|
||||
return set_nvme_err(out, status);
|
||||
|
||||
out.result = nvm_reply[2];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// sntrealtek_device
|
||||
|
||||
class sntrealtek_device
|
||||
: public tunnelled_device<
|
||||
/*implements*/ nvme_device,
|
||||
/*by tunnelling through a*/ scsi_device>
|
||||
{
|
||||
public:
|
||||
sntrealtek_device(smart_interface *intf, scsi_device *scsidev,
|
||||
const char *req_type, unsigned nsid);
|
||||
|
||||
virtual ~sntrealtek_device();
|
||||
|
||||
virtual bool nvme_pass_through(const nvme_cmd_in &in, nvme_cmd_out &out) override;
|
||||
};
|
||||
|
||||
sntrealtek_device::sntrealtek_device(smart_interface *intf, scsi_device *scsidev,
|
||||
const char *req_type, unsigned nsid)
|
||||
: smart_device(intf, scsidev->get_dev_name(), "sntrealtek", req_type),
|
||||
tunnelled_device<nvme_device, scsi_device>(scsidev, nsid)
|
||||
{
|
||||
set_info().info_name = strprintf("%s [USB NVMe Realtek]", scsidev->get_info_name());
|
||||
}
|
||||
|
||||
sntrealtek_device::~sntrealtek_device()
|
||||
{
|
||||
}
|
||||
|
||||
bool sntrealtek_device::nvme_pass_through(const nvme_cmd_in &in, nvme_cmd_out & /* out */)
|
||||
{
|
||||
unsigned size = in.size;
|
||||
switch (in.opcode)
|
||||
{
|
||||
case smartmontools::nvme_admin_identify:
|
||||
if (in.cdw10 == 0x0000001) // Identify controller
|
||||
break;
|
||||
if (in.cdw10 == 0x0000000)
|
||||
{ // Identify namespace
|
||||
if (in.nsid == 1)
|
||||
break;
|
||||
return set_err(ENOSYS, "NVMe Identify Namespace 0x%x not supported", in.nsid);
|
||||
}
|
||||
return set_err(ENOSYS, "NVMe Identify with CDW10=0x%08x not supported", in.cdw10);
|
||||
case smartmontools::nvme_admin_get_log_page:
|
||||
if (!(in.nsid == 0xffffffff || !in.nsid))
|
||||
return set_err(ENOSYS, "NVMe Get Log Page with NSID=0x%x not supported", in.nsid);
|
||||
if (size > 0x200)
|
||||
{ // Reading more apparently returns old data from previous command
|
||||
// TODO: Add ability to return short reads to caller
|
||||
size = 0x200;
|
||||
pout("Warning: NVMe Get Log truncated to 0x%03x bytes, 0x%03x bytes zero filled\n", size, in.size - size);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return set_err(ENOSYS, "NVMe admin command 0x%02x not supported", in.opcode);
|
||||
break;
|
||||
}
|
||||
if (in.cdw11 || in.cdw12 || in.cdw13 || in.cdw14 || in.cdw15)
|
||||
return set_err(ENOSYS, "Nonzero NVMe command dwords 11-15 not supported");
|
||||
|
||||
uint8_t cdb[16] = {
|
||||
0,
|
||||
};
|
||||
cdb[0] = 0xe4;
|
||||
sg_put_unaligned_le16(size, cdb + 1);
|
||||
cdb[3] = in.opcode;
|
||||
cdb[4] = (uint8_t)in.cdw10;
|
||||
|
||||
scsi_cmnd_io io_hdr = {};
|
||||
io_hdr.cmnd = cdb;
|
||||
io_hdr.cmnd_len = sizeof(cdb);
|
||||
io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
|
||||
io_hdr.dxferp = (uint8_t *)in.buffer;
|
||||
io_hdr.dxfer_len = size;
|
||||
memset(in.buffer, 0, in.size);
|
||||
|
||||
scsi_device *scsidev = get_tunnel_dev();
|
||||
if (!scsidev->scsi_pass_through_and_check(&io_hdr, "sntrealtek_device::nvme_pass_through: "))
|
||||
return set_err(scsidev->get_err());
|
||||
|
||||
// out.result = ?; // TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace snt
|
||||
|
||||
using namespace snt;
|
||||
|
||||
nvme_device *smart_interface::get_snt_device(const char *type, scsi_device *scsidev)
|
||||
{
|
||||
if (!scsidev)
|
||||
throw std::logic_error("smart_interface: get_snt_device() called with scsidev=0");
|
||||
|
||||
// Take temporary ownership of 'scsidev' to delete it on error
|
||||
scsi_device_auto_ptr scsidev_holder(scsidev);
|
||||
nvme_device *sntdev = 0;
|
||||
|
||||
// TODO: Remove this and adjust drivedb entry accordingly when no longer EXPERIMENTAL
|
||||
if (!strcmp(type, "sntjmicron#please_try"))
|
||||
{
|
||||
set_err(EINVAL, "USB to NVMe bridge [please try '-d sntjmicron' and report result to: " PACKAGE_BUGREPORT "]");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(type, "sntasmedia"))
|
||||
{
|
||||
// No namespace supported
|
||||
sntdev = new sntasmedia_device(this, scsidev, type, 0xffffffff);
|
||||
}
|
||||
|
||||
else if (!strncmp(type, "sntjmicron", 10))
|
||||
{
|
||||
int n1 = -1, n2 = -1, len = strlen(type);
|
||||
unsigned nsid = 0; // invalid namespace id -> use default
|
||||
sscanf(type, "sntjmicron%n,0x%x%n", &n1, &nsid, &n2);
|
||||
if (!(n1 == len || n2 == len))
|
||||
{
|
||||
set_err(EINVAL, "Invalid NVMe namespace id in '%s'", type);
|
||||
return 0;
|
||||
}
|
||||
sntdev = new sntjmicron_device(this, scsidev, type, nsid);
|
||||
}
|
||||
|
||||
else if (!strcmp(type, "sntrealtek"))
|
||||
{
|
||||
// No namespace supported
|
||||
sntdev = new sntrealtek_device(this, scsidev, type, 0xffffffff);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
set_err(EINVAL, "Unknown SNT device type '%s'", type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 'scsidev' is now owned by 'sntdev'
|
||||
scsidev_holder.release();
|
||||
return sntdev;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* scsiprint.h
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2002-9 Bruce Allen
|
||||
* Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
|
||||
*
|
||||
* Additional SCSI work:
|
||||
* Copyright (C) 2003-18 Douglas Gilbert <dgilbert@interlog.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef SCSI_PRINT_H_
|
||||
#define SCSI_PRINT_H_
|
||||
|
||||
#define SCSIPRINT_H_CVSID "$Id: scsiprint.h 5334 2022-02-26 01:02:56Z dpgilbert $\n"
|
||||
|
||||
// Options for scsiPrintMain
|
||||
struct scsi_print_options
|
||||
{
|
||||
bool drive_info = false;
|
||||
bool smart_check_status = false;
|
||||
bool smart_vendor_attrib = false;
|
||||
bool smart_error_log = false;
|
||||
bool smart_selftest_log = false;
|
||||
bool smart_background_log = false;
|
||||
bool smart_ss_media_log = false;
|
||||
|
||||
bool smart_disable = false, smart_enable = false;
|
||||
bool smart_auto_save_disable = false, smart_auto_save_enable = false;
|
||||
|
||||
bool smart_default_selftest = false;
|
||||
bool smart_short_selftest = false, smart_short_cap_selftest = false;
|
||||
bool smart_extend_selftest = false, smart_extend_cap_selftest = false;
|
||||
bool smart_selftest_abort = false;
|
||||
bool smart_selftest_force = false; // Ignore already running test
|
||||
bool scsi_pending_defects = false;
|
||||
|
||||
bool smart_env_rep = false;
|
||||
|
||||
bool sasphy = false, sasphy_reset = false;
|
||||
|
||||
bool tape_device_stats = false;
|
||||
bool tape_alert = false;
|
||||
|
||||
bool zoned_device_stats = false;
|
||||
|
||||
bool get_wce = false, get_rcd = false;
|
||||
short int set_wce = 0, set_rcd = 0; // disable(-1), enable(1) cache
|
||||
|
||||
unsigned char powermode = 0; // Enhancement Skip check, if disk in idle or standby mode
|
||||
unsigned char powerexit = 0; // exit() code for low power mode
|
||||
|
||||
int set_standby = 0; // set(1..255->0..254) standby timer
|
||||
bool set_standby_now = false; // set drive to standby
|
||||
bool set_active = false; // set drive to active
|
||||
|
||||
int health_opt_count = 0; // TapeAlert log page only read if this value > 1
|
||||
};
|
||||
|
||||
int scsiPrintMain(scsi_device *device, const scsi_print_options &options);
|
||||
|
||||
#endif
|
|
@ -1,490 +0,0 @@
|
|||
#ifndef SG_UNALIGNED_H
|
||||
#define SG_UNALIGNED_H
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014-2018 Douglas Gilbert.
|
||||
* All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style
|
||||
* license that can be found in the BSD_LICENSE file.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h> /* for uint8_t and friends */
|
||||
#include <string.h> /* for memcpy */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* These inline functions convert integers (always unsigned) to byte streams
|
||||
* and vice versa. They have two goals:
|
||||
* - change the byte ordering of integers between host order and big
|
||||
* endian ("_be") or little endian ("_le")
|
||||
* - copy the big or little endian byte stream so it complies with any
|
||||
* alignment that host integers require
|
||||
*
|
||||
* Host integer to given endian byte stream is a "_put_" function taking
|
||||
* two arguments (integer and pointer to byte stream) returning void.
|
||||
* Given endian byte stream to host integer is a "_get_" function that takes
|
||||
* one argument and returns an integer of appropriate size (uint32_t for 24
|
||||
* bit operations, uint64_t for 48 bit operations).
|
||||
*
|
||||
* Big endian byte format "on the wire" is the default used by SCSI
|
||||
* standards (www.t10.org). Big endian is also the network byte order.
|
||||
* Little endian is used by ATA, PCI and NVMe.
|
||||
*/
|
||||
|
||||
/* The generic form of these routines was borrowed from the Linux kernel,
|
||||
* via mhvtl. There is a specialised version of the main functions for
|
||||
* little endian or big endian provided that not-quite-standard defines for
|
||||
* endianness are available from the compiler and the <byteswap.h> header
|
||||
* (a GNU extension) has been detected by ./configure . To force the
|
||||
* generic version, use './configure --disable-fast-lebe ' . */
|
||||
|
||||
/* Note: Assumes that the source and destination locations do not overlap.
|
||||
* An example of overlapping source and destination:
|
||||
* sg_put_unaligned_le64(j, ((uint8_t *)&j) + 1);
|
||||
* Best not to do things like that.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h" /* need this to see if HAVE_BYTESWAP_H */
|
||||
#endif
|
||||
|
||||
#undef GOT_UNALIGNED_SPECIALS /* just in case */
|
||||
|
||||
#if defined(__BYTE_ORDER__) && defined(HAVE_BYTESWAP_H) && \
|
||||
!defined(IGNORE_FAST_LEBE)
|
||||
|
||||
#if defined(__LITTLE_ENDIAN__) || (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||
|
||||
#define GOT_UNALIGNED_SPECIALS 1
|
||||
|
||||
#include <byteswap.h> /* for bswap_16(), bswap_32() and bswap_64() */
|
||||
|
||||
// #warning ">>>>>> Doing Little endian special unaligneds"
|
||||
|
||||
static inline uint16_t sg_get_unaligned_be16(const void *p)
|
||||
{
|
||||
uint16_t u;
|
||||
|
||||
memcpy(&u, p, 2);
|
||||
return bswap_16(u);
|
||||
}
|
||||
|
||||
static inline uint32_t sg_get_unaligned_be32(const void *p)
|
||||
{
|
||||
uint32_t u;
|
||||
|
||||
memcpy(&u, p, 4);
|
||||
return bswap_32(u);
|
||||
}
|
||||
|
||||
static inline uint64_t sg_get_unaligned_be64(const void *p)
|
||||
{
|
||||
uint64_t u;
|
||||
|
||||
memcpy(&u, p, 8);
|
||||
return bswap_64(u);
|
||||
}
|
||||
|
||||
static inline void sg_put_unaligned_be16(uint16_t val, void *p)
|
||||
{
|
||||
uint16_t u = bswap_16(val);
|
||||
|
||||
memcpy(p, &u, 2);
|
||||
}
|
||||
|
||||
static inline void sg_put_unaligned_be32(uint32_t val, void *p)
|
||||
{
|
||||
uint32_t u = bswap_32(val);
|
||||
|
||||
memcpy(p, &u, 4);
|
||||
}
|
||||
|
||||
static inline void sg_put_unaligned_be64(uint64_t val, void *p)
|
||||
{
|
||||
uint64_t u = bswap_64(val);
|
||||
|
||||
memcpy(p, &u, 8);
|
||||
}
|
||||
|
||||
static inline uint16_t sg_get_unaligned_le16(const void *p)
|
||||
{
|
||||
uint16_t u;
|
||||
|
||||
memcpy(&u, p, 2);
|
||||
return u;
|
||||
}
|
||||
|
||||
static inline uint32_t sg_get_unaligned_le32(const void *p)
|
||||
{
|
||||
uint32_t u;
|
||||
|
||||
memcpy(&u, p, 4);
|
||||
return u;
|
||||
}
|
||||
|
||||
static inline uint64_t sg_get_unaligned_le64(const void *p)
|
||||
{
|
||||
uint64_t u;
|
||||
|
||||
memcpy(&u, p, 8);
|
||||
return u;
|
||||
}
|
||||
|
||||
static inline void sg_put_unaligned_le16(uint16_t val, void *p)
|
||||
{
|
||||
memcpy(p, &val, 2);
|
||||
}
|
||||
|
||||
static inline void sg_put_unaligned_le32(uint32_t val, void *p)
|
||||
{
|
||||
memcpy(p, &val, 4);
|
||||
}
|
||||
|
||||
static inline void sg_put_unaligned_le64(uint64_t val, void *p)
|
||||
{
|
||||
memcpy(p, &val, 8);
|
||||
}
|
||||
|
||||
#elif defined(__BIG_ENDIAN__) || (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||
|
||||
#define GOT_UNALIGNED_SPECIALS 1
|
||||
|
||||
#include <byteswap.h>
|
||||
|
||||
// #warning ">>>>>> Doing BIG endian special unaligneds"
|
||||
|
||||
static inline uint16_t sg_get_unaligned_le16(const void *p)
|
||||
{
|
||||
uint16_t u;
|
||||
|
||||
memcpy(&u, p, 2);
|
||||
return bswap_16(u);
|
||||
}
|
||||
|
||||
static inline uint32_t sg_get_unaligned_le32(const void *p)
|
||||
{
|
||||
uint32_t u;
|
||||
|
||||
memcpy(&u, p, 4);
|
||||
return bswap_32(u);
|
||||
}
|
||||
|
||||
static inline uint64_t sg_get_unaligned_le64(const void *p)
|
||||
{
|
||||
uint64_t u;
|
||||
|
||||
memcpy(&u, p, 8);
|
||||
return bswap_64(u);
|
||||
}
|
||||
|
||||
static inline void sg_put_unaligned_le16(uint16_t val, void *p)
|
||||
{
|
||||
uint16_t u = bswap_16(val);
|
||||
|
||||
memcpy(p, &u, 2);
|
||||
}
|
||||
|
||||
static inline void sg_put_unaligned_le32(uint32_t val, void *p)
|
||||
{
|
||||
uint32_t u = bswap_32(val);
|
||||
|
||||
memcpy(p, &u, 4);
|
||||
}
|
||||
|
||||
static inline void sg_put_unaligned_le64(uint64_t val, void *p)
|
||||
{
|
||||
uint64_t u = bswap_64(val);
|
||||
|
||||
memcpy(p, &u, 8);
|
||||
}
|
||||
|
||||
static inline uint16_t sg_get_unaligned_be16(const void *p)
|
||||
{
|
||||
uint16_t u;
|
||||
|
||||
memcpy(&u, p, 2);
|
||||
return u;
|
||||
}
|
||||
|
||||
static inline uint32_t sg_get_unaligned_be32(const void *p)
|
||||
{
|
||||
uint32_t u;
|
||||
|
||||
memcpy(&u, p, 4);
|
||||
return u;
|
||||
}
|
||||
|
||||
static inline uint64_t sg_get_unaligned_be64(const void *p)
|
||||
{
|
||||
uint64_t u;
|
||||
|
||||
memcpy(&u, p, 8);
|
||||
return u;
|
||||
}
|
||||
|
||||
static inline void sg_put_unaligned_be16(uint16_t val, void *p)
|
||||
{
|
||||
memcpy(p, &val, 2);
|
||||
}
|
||||
|
||||
static inline void sg_put_unaligned_be32(uint32_t val, void *p)
|
||||
{
|
||||
memcpy(p, &val, 4);
|
||||
}
|
||||
|
||||
static inline void sg_put_unaligned_be64(uint64_t val, void *p)
|
||||
{
|
||||
memcpy(p, &val, 8);
|
||||
}
|
||||
|
||||
#endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */
|
||||
#endif /* #if defined __BYTE_ORDER__ && defined <byteswap.h> && \
|
||||
* ! defined IGNORE_FAST_LEBE */
|
||||
|
||||
#ifndef GOT_UNALIGNED_SPECIALS
|
||||
|
||||
/* Now we have no tricks left, so use the only way this can be done
|
||||
* correctly in C safely: lots of shifts. */
|
||||
|
||||
// #warning ">>>>>> Doing GENERIC unaligneds"
|
||||
|
||||
static inline uint16_t sg_get_unaligned_be16(const void *p)
|
||||
{
|
||||
return ((const uint8_t *)p)[0] << 8 | ((const uint8_t *)p)[1];
|
||||
}
|
||||
|
||||
static inline uint32_t sg_get_unaligned_be32(const void *p)
|
||||
{
|
||||
return ((const uint8_t *)p)[0] << 24 | ((const uint8_t *)p)[1] << 16 |
|
||||
((const uint8_t *)p)[2] << 8 | ((const uint8_t *)p)[3];
|
||||
}
|
||||
|
||||
static inline uint64_t sg_get_unaligned_be64(const void *p)
|
||||
{
|
||||
return (uint64_t)sg_get_unaligned_be32(p) << 32 |
|
||||
sg_get_unaligned_be32((const uint8_t *)p + 4);
|
||||
}
|
||||
|
||||
static inline void sg_put_unaligned_be16(uint16_t val, void *p)
|
||||
{
|
||||
((uint8_t *)p)[0] = (uint8_t)(val >> 8);
|
||||
((uint8_t *)p)[1] = (uint8_t)val;
|
||||
}
|
||||
|
||||
static inline void sg_put_unaligned_be32(uint32_t val, void *p)
|
||||
{
|
||||
sg_put_unaligned_be16(val >> 16, p);
|
||||
sg_put_unaligned_be16(val, (uint8_t *)p + 2);
|
||||
}
|
||||
|
||||
static inline void sg_put_unaligned_be64(uint64_t val, void *p)
|
||||
{
|
||||
sg_put_unaligned_be32(val >> 32, p);
|
||||
sg_put_unaligned_be32(val, (uint8_t *)p + 4);
|
||||
}
|
||||
|
||||
static inline uint16_t sg_get_unaligned_le16(const void *p)
|
||||
{
|
||||
return ((const uint8_t *)p)[1] << 8 | ((const uint8_t *)p)[0];
|
||||
}
|
||||
|
||||
static inline uint32_t sg_get_unaligned_le32(const void *p)
|
||||
{
|
||||
return ((const uint8_t *)p)[3] << 24 | ((const uint8_t *)p)[2] << 16 |
|
||||
((const uint8_t *)p)[1] << 8 | ((const uint8_t *)p)[0];
|
||||
}
|
||||
|
||||
static inline uint64_t sg_get_unaligned_le64(const void *p)
|
||||
{
|
||||
return (uint64_t)sg_get_unaligned_le32((const uint8_t *)p + 4) << 32 |
|
||||
sg_get_unaligned_le32(p);
|
||||
}
|
||||
|
||||
static inline void sg_put_unaligned_le16(uint16_t val, void *p)
|
||||
{
|
||||
((uint8_t *)p)[0] = val & 0xff;
|
||||
((uint8_t *)p)[1] = val >> 8;
|
||||
}
|
||||
|
||||
static inline void sg_put_unaligned_le32(uint32_t val, void *p)
|
||||
{
|
||||
sg_put_unaligned_le16(val >> 16, (uint8_t *)p + 2);
|
||||
sg_put_unaligned_le16(val, p);
|
||||
}
|
||||
|
||||
static inline void sg_put_unaligned_le64(uint64_t val, void *p)
|
||||
{
|
||||
sg_put_unaligned_le32(val >> 32, (uint8_t *)p + 4);
|
||||
sg_put_unaligned_le32(val, p);
|
||||
}
|
||||
|
||||
#endif /* #ifndef GOT_UNALIGNED_SPECIALS */
|
||||
|
||||
/* Following are lesser used conversions that don't have specializations
|
||||
* for endianness; big endian first. In summary these are the 24, 48 bit and
|
||||
* given-length conversions plus the "nz" conditional put conversions. */
|
||||
|
||||
/* Now big endian, get 24+48 then put 24+48 */
|
||||
static inline uint32_t sg_get_unaligned_be24(const void *p)
|
||||
{
|
||||
return ((const uint8_t *)p)[0] << 16 | ((const uint8_t *)p)[1] << 8 |
|
||||
((const uint8_t *)p)[2];
|
||||
}
|
||||
|
||||
/* Assume 48 bit value placed in uint64_t */
|
||||
static inline uint64_t sg_get_unaligned_be48(const void *p)
|
||||
{
|
||||
return (uint64_t)sg_get_unaligned_be16(p) << 32 |
|
||||
sg_get_unaligned_be32((const uint8_t *)p + 2);
|
||||
}
|
||||
|
||||
/* Returns 0 if 'num_bytes' is less than or equal to 0 or greater than
|
||||
* 8 (i.e. sizeof(uint64_t)). Else returns result in uint64_t which is
|
||||
* an 8 byte unsigned integer. */
|
||||
static inline uint64_t sg_get_unaligned_be(int num_bytes, const void *p)
|
||||
{
|
||||
if ((num_bytes <= 0) || (num_bytes > (int)sizeof(uint64_t)))
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
const uint8_t *xp = (const uint8_t *)p;
|
||||
uint64_t res = *xp;
|
||||
|
||||
for (++xp; num_bytes > 1; ++xp, --num_bytes)
|
||||
res = (res << 8) | *xp;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void sg_put_unaligned_be24(uint32_t val, void *p)
|
||||
{
|
||||
((uint8_t *)p)[0] = (val >> 16) & 0xff;
|
||||
((uint8_t *)p)[1] = (val >> 8) & 0xff;
|
||||
((uint8_t *)p)[2] = val & 0xff;
|
||||
}
|
||||
|
||||
/* Assume 48 bit value placed in uint64_t */
|
||||
static inline void sg_put_unaligned_be48(uint64_t val, void *p)
|
||||
{
|
||||
sg_put_unaligned_be16(val >> 32, p);
|
||||
sg_put_unaligned_be32(val, (uint8_t *)p + 2);
|
||||
}
|
||||
|
||||
/* Now little endian, get 24+48 then put 24+48 */
|
||||
static inline uint32_t sg_get_unaligned_le24(const void *p)
|
||||
{
|
||||
return (uint32_t)sg_get_unaligned_le16(p) |
|
||||
((const uint8_t *)p)[2] << 16;
|
||||
}
|
||||
|
||||
/* Assume 48 bit value placed in uint64_t */
|
||||
static inline uint64_t sg_get_unaligned_le48(const void *p)
|
||||
{
|
||||
return (uint64_t)sg_get_unaligned_le16((const uint8_t *)p + 4) << 32 |
|
||||
sg_get_unaligned_le32(p);
|
||||
}
|
||||
|
||||
static inline void sg_put_unaligned_le24(uint32_t val, void *p)
|
||||
{
|
||||
((uint8_t *)p)[2] = (val >> 16) & 0xff;
|
||||
((uint8_t *)p)[1] = (val >> 8) & 0xff;
|
||||
((uint8_t *)p)[0] = val & 0xff;
|
||||
}
|
||||
|
||||
/* Assume 48 bit value placed in uint64_t */
|
||||
static inline void sg_put_unaligned_le48(uint64_t val, void *p)
|
||||
{
|
||||
((uint8_t *)p)[5] = (val >> 40) & 0xff;
|
||||
((uint8_t *)p)[4] = (val >> 32) & 0xff;
|
||||
((uint8_t *)p)[3] = (val >> 24) & 0xff;
|
||||
((uint8_t *)p)[2] = (val >> 16) & 0xff;
|
||||
((uint8_t *)p)[1] = (val >> 8) & 0xff;
|
||||
((uint8_t *)p)[0] = val & 0xff;
|
||||
}
|
||||
|
||||
/* Returns 0 if 'num_bytes' is less than or equal to 0 or greater than
|
||||
* 8 (i.e. sizeof(uint64_t)). Else returns result in uint64_t which is
|
||||
* an 8 byte unsigned integer. */
|
||||
static inline uint64_t sg_get_unaligned_le(int num_bytes, const void *p)
|
||||
{
|
||||
if ((num_bytes <= 0) || (num_bytes > (int)sizeof(uint64_t)))
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
const uint8_t *xp = (const uint8_t *)p + (num_bytes - 1);
|
||||
uint64_t res = *xp;
|
||||
|
||||
for (--xp; num_bytes > 1; --xp, --num_bytes)
|
||||
res = (res << 8) | *xp;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/* Since cdb and parameter blocks are often memset to zero before these
|
||||
* unaligned function partially fill them, then check for a val of zero
|
||||
* and ignore if it is with these variants. First big endian, then little */
|
||||
static inline void sg_nz_put_unaligned_be16(uint16_t val, void *p)
|
||||
{
|
||||
if (val)
|
||||
sg_put_unaligned_be16(val, p);
|
||||
}
|
||||
|
||||
static inline void sg_nz_put_unaligned_be24(uint32_t val, void *p)
|
||||
{
|
||||
if (val)
|
||||
{
|
||||
((uint8_t *)p)[0] = (val >> 16) & 0xff;
|
||||
((uint8_t *)p)[1] = (val >> 8) & 0xff;
|
||||
((uint8_t *)p)[2] = val & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void sg_nz_put_unaligned_be32(uint32_t val, void *p)
|
||||
{
|
||||
if (val)
|
||||
sg_put_unaligned_be32(val, p);
|
||||
}
|
||||
|
||||
static inline void sg_nz_put_unaligned_be64(uint64_t val, void *p)
|
||||
{
|
||||
if (val)
|
||||
sg_put_unaligned_be64(val, p);
|
||||
}
|
||||
|
||||
static inline void sg_nz_put_unaligned_le16(uint16_t val, void *p)
|
||||
{
|
||||
if (val)
|
||||
sg_put_unaligned_le16(val, p);
|
||||
}
|
||||
|
||||
static inline void sg_nz_put_unaligned_le24(uint32_t val, void *p)
|
||||
{
|
||||
if (val)
|
||||
{
|
||||
((uint8_t *)p)[2] = (val >> 16) & 0xff;
|
||||
((uint8_t *)p)[1] = (val >> 8) & 0xff;
|
||||
((uint8_t *)p)[0] = val & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void sg_nz_put_unaligned_le32(uint32_t val, void *p)
|
||||
{
|
||||
if (val)
|
||||
sg_put_unaligned_le32(val, p);
|
||||
}
|
||||
|
||||
static inline void sg_nz_put_unaligned_le64(uint64_t val, void *p)
|
||||
{
|
||||
if (val)
|
||||
sg_put_unaligned_le64(val, p);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SG_UNALIGNED_H */
|
|
@ -1,587 +0,0 @@
|
|||
/*
|
||||
* smartctl.cpp
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2002-11 Bruce Allen
|
||||
* Copyright (C) 2008-21 Christian Franke
|
||||
* Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#define __STDC_FORMAT_MACROS 1 // enable PRI* for C++
|
||||
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdexcept>
|
||||
#include <getopt.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#include "atacmds.h"
|
||||
#include "dev_interface.h"
|
||||
#include "ataprint.h"
|
||||
#include "knowndrives.h"
|
||||
#include "scsicmds.h"
|
||||
#include "scsiprint.h"
|
||||
#include "nvmeprint.h"
|
||||
#include "smartctl.h"
|
||||
#include "utility.h"
|
||||
|
||||
const char *smartctl_cpp_cvsid = "$Id: smartctl.cpp 5333 2022-02-26 00:15:22Z dpgilbert $" CONFIG_H_CVSID SMARTCTL_H_CVSID;
|
||||
|
||||
// Globals to control printing
|
||||
bool printing_is_switchable = false;
|
||||
bool printing_is_off = false;
|
||||
std::string nvmeTemp = "";
|
||||
std::string sataTemp = "";
|
||||
|
||||
// Control JSON output
|
||||
json jglb;
|
||||
static bool print_as_json = false;
|
||||
static json::print_options print_as_json_options;
|
||||
static bool print_as_json_output = false;
|
||||
static bool print_as_json_impl = false;
|
||||
static bool print_as_json_unimpl = false;
|
||||
|
||||
static void printslogan()
|
||||
{
|
||||
jout("%s\n", format_version_info("smartctl").c_str());
|
||||
}
|
||||
|
||||
static void UsageSummary()
|
||||
{
|
||||
pout("\nUse smartctl -h to get a usage summary\n\n");
|
||||
return;
|
||||
}
|
||||
|
||||
static void js_initialize(int argc, char **argv, bool verbose)
|
||||
{
|
||||
if (jglb.is_enabled())
|
||||
return;
|
||||
jglb.enable();
|
||||
if (verbose)
|
||||
jglb.set_verbose();
|
||||
|
||||
// Major.minor version of JSON format
|
||||
jglb["json_format_version"][0] = 1;
|
||||
jglb["json_format_version"][1] = 0;
|
||||
|
||||
// Smartctl version info
|
||||
json::ref jref = jglb["smartctl"];
|
||||
int ver[3] = {0, 0, 0};
|
||||
sscanf(PACKAGE_VERSION, "%d.%d.%d", ver, ver + 1, ver + 2);
|
||||
jref["version"][0] = ver[0];
|
||||
jref["version"][1] = ver[1];
|
||||
if (ver[2] > 0)
|
||||
jref["version"][2] = ver[2];
|
||||
|
||||
#ifdef SMARTMONTOOLS_SVN_REV
|
||||
jref["svn_revision"] = SMARTMONTOOLS_SVN_REV;
|
||||
#endif
|
||||
jref["platform_info"] = smi()->get_os_version_str();
|
||||
#ifdef BUILD_INFO
|
||||
jref["build_info"] = BUILD_INFO;
|
||||
#endif
|
||||
|
||||
jref["argv"][0] = "smartctl";
|
||||
for (int i = 1; i < argc; i++)
|
||||
jref["argv"][i] = argv[i];
|
||||
}
|
||||
|
||||
static std::string getvalidarglist(int opt);
|
||||
|
||||
// Values for --long only options, see parse_options()
|
||||
enum
|
||||
{
|
||||
opt_identify = 1000,
|
||||
opt_scan,
|
||||
opt_scan_open,
|
||||
opt_set,
|
||||
opt_smart
|
||||
};
|
||||
|
||||
/* Returns a string containing a formatted list of the valid arguments
|
||||
to the option opt or empty on failure. Note 'v' case different */
|
||||
static std::string getvalidarglist(int opt)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'q':
|
||||
return "errorsonly, silent, noserial";
|
||||
case 'd':
|
||||
return smi()->get_valid_dev_types_str() + ", auto, test";
|
||||
case 'T':
|
||||
return "normal, conservative, permissive, verypermissive";
|
||||
case 'b':
|
||||
return "warn, exit, ignore";
|
||||
case 'B':
|
||||
return "[+]<FILE_NAME>";
|
||||
case 'r':
|
||||
return "ioctl[,N], ataioctl[,N], scsiioctl[,N], nvmeioctl[,N]";
|
||||
case opt_smart:
|
||||
case 'o':
|
||||
case 'S':
|
||||
return "on, off";
|
||||
case 'l':
|
||||
return "error, selftest, selective, directory[,g|s], "
|
||||
"xerror[,N][,error], xselftest[,N][,selftest], "
|
||||
"background, sasphy[,reset], sataphy[,reset], "
|
||||
"scttemp[sts,hist], scttempint,N[,p], "
|
||||
"scterc[,N,M][,p|reset], devstat[,N], defects[,N], "
|
||||
"ssd, gplog,N[,RANGE], smartlog,N[,RANGE], "
|
||||
"nvmelog,N,SIZE, tapedevstat, zdevstat, envrep";
|
||||
case 'P':
|
||||
return "use, ignore, show, showall";
|
||||
case 't':
|
||||
return "offline, short, long, conveyance, force, vendor,N, select,M-N, "
|
||||
"pending,N, afterselect,[on|off]";
|
||||
case 'F':
|
||||
return std::string(get_valid_firmwarebug_args()) + ", swapid";
|
||||
case 'n':
|
||||
return "never, sleep[,STATUS[,STATUS2]], standby[,STATUS[,STATUS2]], "
|
||||
"idle[,STATUS[,STATUS2]]";
|
||||
case 'f':
|
||||
return "old, brief, hex[,id|val]";
|
||||
case 'g':
|
||||
return "aam, apm, dsn, lookahead, security, wcache, rcache, wcreorder, wcache-sct";
|
||||
case opt_set:
|
||||
return "aam,[N|off], apm,[N|off], dsn,[on|off], lookahead,[on|off], security-freeze, "
|
||||
"standby,[N|off|now], wcache,[on|off], rcache,[on|off], wcreorder,[on|off[,p]], "
|
||||
"wcache-sct,[ata|on|off[,p]]";
|
||||
case 's':
|
||||
return getvalidarglist(opt_smart) + ", " + getvalidarglist(opt_set);
|
||||
case 'j':
|
||||
return "c, g, i, o, s, u, v, y";
|
||||
case opt_identify:
|
||||
return "n, wn, w, v, wv, wb";
|
||||
case 'v':
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/* Prints the message "=======> VALID ARGUMENTS ARE: <LIST> \n", where
|
||||
<LIST> is the list of valid arguments for option opt. */
|
||||
static void printvalidarglistmessage(int opt)
|
||||
{
|
||||
if (opt == 'v')
|
||||
{
|
||||
jerr("=======> VALID ARGUMENTS ARE:\n\thelp\n%s\n<=======\n",
|
||||
create_vendor_attribute_arg_list().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// getvalidarglist() might produce a multiline or single line string. We
|
||||
// need to figure out which to get the formatting right.
|
||||
std::string s = getvalidarglist(opt);
|
||||
char separator = strchr(s.c_str(), '\n') ? '\n' : ' ';
|
||||
jerr("=======> VALID ARGUMENTS ARE:%c%s%c<=======\n", separator, s.c_str(), separator);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Checksum error mode
|
||||
enum checksum_err_mode_t
|
||||
{
|
||||
CHECKSUM_ERR_WARN,
|
||||
CHECKSUM_ERR_EXIT,
|
||||
CHECKSUM_ERR_IGNORE
|
||||
};
|
||||
|
||||
static checksum_err_mode_t checksum_err_mode = CHECKSUM_ERR_WARN;
|
||||
|
||||
static void scan_devices(const smart_devtype_list &types, bool with_open, char **argv);
|
||||
|
||||
// Printing functions
|
||||
|
||||
__attribute_format_printf(3, 0) static void vjpout(bool is_js_impl, const char *msg_severity,
|
||||
const char *fmt, va_list ap)
|
||||
{
|
||||
if (!print_as_json)
|
||||
{
|
||||
// Print out directly
|
||||
vprintf(fmt, ap);
|
||||
fflush(stdout);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add lines to JSON output
|
||||
static char buf[1024];
|
||||
static char *bufnext = buf;
|
||||
vsnprintf(bufnext, sizeof(buf) - (bufnext - buf), fmt, ap);
|
||||
for (char *p = buf, *q;; p = q)
|
||||
{
|
||||
if (!(q = strchr(p, '\n')))
|
||||
{
|
||||
// Keep remaining line for next call
|
||||
for (bufnext = buf; *p; bufnext++, p++)
|
||||
*bufnext = *p;
|
||||
break;
|
||||
}
|
||||
*q++ = 0; // '\n' -> '\0'
|
||||
|
||||
static int lineno = 0;
|
||||
lineno++;
|
||||
if (print_as_json_output)
|
||||
{
|
||||
// Collect full output in array
|
||||
static int outindex = 0;
|
||||
jglb["smartctl"]["output"][outindex++] = p;
|
||||
}
|
||||
if (!*p)
|
||||
continue; // Skip empty line
|
||||
|
||||
if (msg_severity)
|
||||
{
|
||||
// Collect non-empty messages in array
|
||||
static int errindex = 0;
|
||||
json::ref jref = jglb["smartctl"]["messages"][errindex++];
|
||||
jref["string"] = p;
|
||||
jref["severity"] = msg_severity;
|
||||
}
|
||||
|
||||
if ((is_js_impl && print_as_json_impl) || (!is_js_impl && print_as_json_unimpl))
|
||||
{
|
||||
// Add (un)implemented non-empty lines to global object
|
||||
jglb[strprintf("smartctl_%04d_%c", lineno,
|
||||
(is_js_impl ? 'i' : 'u'))
|
||||
.c_str()] = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default: print to stdout
|
||||
// --json: ignore
|
||||
// --json=o: append to "output" array
|
||||
// --json=u: add "smartctl_NNNN_u" element(s)
|
||||
void pout(const char *fmt, ...)
|
||||
{
|
||||
if (printing_is_off)
|
||||
return;
|
||||
if (print_as_json && !(print_as_json_output || print_as_json_impl || print_as_json_unimpl))
|
||||
return;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vjpout(false, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
// Default: Print to stdout
|
||||
// --json: ignore
|
||||
// --json=o: append to "output" array
|
||||
// --json=i: add "smartctl_NNNN_i" element(s)
|
||||
void jout(const char *fmt, ...)
|
||||
{
|
||||
if (printing_is_off)
|
||||
return;
|
||||
if (print_as_json && !(print_as_json_output || print_as_json_impl || print_as_json_unimpl))
|
||||
return;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vjpout(true, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
// Default: print to stdout
|
||||
// --json: append to "messages"
|
||||
// --json=o: append to "output" array
|
||||
// --json=i: add "smartctl_NNNN_i" element(s)
|
||||
void jinf(const char *fmt, ...)
|
||||
{
|
||||
if (printing_is_off)
|
||||
return;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vjpout(true, "information", fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void jwrn(const char *fmt, ...)
|
||||
{
|
||||
if (printing_is_off)
|
||||
return;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vjpout(true, "warning", fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void jerr(const char *fmt, ...)
|
||||
{
|
||||
if (printing_is_off)
|
||||
return;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vjpout(true, "error", fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static char startup_datetime_buf[DATEANDEPOCHLEN];
|
||||
|
||||
// Print smartctl start-up date and time and timezone
|
||||
void jout_startup_datetime(const char *prefix)
|
||||
{
|
||||
jout("%s%s\n", prefix, startup_datetime_buf);
|
||||
}
|
||||
|
||||
// Globals to set failuretest() policy
|
||||
bool failuretest_conservative = false;
|
||||
unsigned char failuretest_permissive = 0;
|
||||
|
||||
// Compares failure type to policy in effect, and either exits or
|
||||
// simply returns to the calling routine.
|
||||
// Used in ataprint.cpp and scsiprint.cpp.
|
||||
void failuretest(failure_type type, int returnvalue)
|
||||
{
|
||||
// If this is an error in an "optional" SMART command
|
||||
if (type == OPTIONAL_CMD)
|
||||
{
|
||||
if (!failuretest_conservative)
|
||||
return;
|
||||
pout("An optional SMART command failed: exiting. Remove '-T conservative' option to continue.\n");
|
||||
throw int(returnvalue);
|
||||
}
|
||||
|
||||
// If this is an error in a "mandatory" SMART command
|
||||
if (type == MANDATORY_CMD)
|
||||
{
|
||||
if (failuretest_permissive--)
|
||||
return;
|
||||
pout("A mandatory SMART command failed: exiting. To continue, add one or more '-T permissive' options.\n");
|
||||
throw int(returnvalue);
|
||||
}
|
||||
|
||||
throw std::logic_error("failuretest: Unknown type");
|
||||
}
|
||||
|
||||
// Used to warn users about invalid checksums. Called from atacmds.cpp.
|
||||
// Action to be taken may be altered by the user.
|
||||
void checksumwarning(const char *string)
|
||||
{
|
||||
// user has asked us to ignore checksum errors
|
||||
if (checksum_err_mode == CHECKSUM_ERR_IGNORE)
|
||||
return;
|
||||
|
||||
pout("Warning! %s error: invalid SMART checksum.\n", string);
|
||||
|
||||
// user has asked us to fail on checksum errors
|
||||
if (checksum_err_mode == CHECKSUM_ERR_EXIT)
|
||||
throw int(FAILSMART);
|
||||
}
|
||||
|
||||
// Return info string about device protocol
|
||||
static const char *get_protocol_info(const smart_device *dev)
|
||||
{
|
||||
switch ((int)dev->is_ata() | ((int)dev->is_scsi() << 1) | ((int)dev->is_nvme() << 2))
|
||||
{
|
||||
case 0x1:
|
||||
return "ATA";
|
||||
case 0x2:
|
||||
return "SCSI";
|
||||
case 0x3:
|
||||
return "ATA+SCSI";
|
||||
case 0x4:
|
||||
return "NVMe";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
// Add JSON device info
|
||||
static void js_device_info(const json::ref &jref, const smart_device *dev)
|
||||
{
|
||||
jref["name"] = dev->get_dev_name();
|
||||
jref["info_name"] = dev->get_info_name();
|
||||
jref["type"] = dev->get_dev_type();
|
||||
jref["protocol"] = get_protocol_info(dev);
|
||||
}
|
||||
|
||||
// Device scan
|
||||
// smartctl [-d type] --scan[-open] -- [PATTERN] [smartd directive ...]
|
||||
void scan_devices(const smart_devtype_list &types, bool with_open, char **argv)
|
||||
{
|
||||
bool dont_print = !(ata_debugmode || scsi_debugmode || nvme_debugmode);
|
||||
|
||||
const char *pattern = 0;
|
||||
int ai = 0;
|
||||
if (argv[ai] && argv[ai][0] != '-')
|
||||
pattern = argv[ai++];
|
||||
|
||||
smart_device_list devlist;
|
||||
printing_is_off = dont_print;
|
||||
bool ok = smi()->scan_smart_devices(devlist, types, pattern);
|
||||
printing_is_off = false;
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
pout("# scan_smart_devices: %s\n", smi()->get_errmsg());
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < devlist.size(); i++)
|
||||
{
|
||||
smart_device_auto_ptr dev(devlist.release(i));
|
||||
json::ref jref = jglb["devices"][i];
|
||||
|
||||
if (with_open)
|
||||
{
|
||||
printing_is_off = dont_print;
|
||||
dev.replace(dev->autodetect_open());
|
||||
printing_is_off = false;
|
||||
}
|
||||
|
||||
js_device_info(jref, dev.get());
|
||||
|
||||
if (with_open && !dev->is_open())
|
||||
{
|
||||
jout("# %s -d %s # %s, %s device open failed: %s\n", dev->get_dev_name(),
|
||||
dev->get_dev_type(), dev->get_info_name(),
|
||||
get_protocol_info(dev.get()), dev->get_errmsg());
|
||||
jref["open_error"] = dev->get_errmsg();
|
||||
continue;
|
||||
}
|
||||
|
||||
jout("%s -d %s", dev->get_dev_name(), dev->get_dev_type());
|
||||
if (!argv[ai])
|
||||
jout(" # %s, %s device\n", dev->get_info_name(), get_protocol_info(dev.get()));
|
||||
else
|
||||
{
|
||||
for (int j = ai; argv[j]; j++)
|
||||
jout(" %s", argv[j]);
|
||||
jout("\n");
|
||||
}
|
||||
|
||||
if (dev->is_open())
|
||||
dev->close();
|
||||
}
|
||||
}
|
||||
|
||||
// Main program without exception handling
|
||||
int main_worker(const char *name)
|
||||
{
|
||||
nvmeTemp.clear();
|
||||
sataTemp.clear();
|
||||
// Throw if runtime environment does not match compile time test.
|
||||
check_config();
|
||||
|
||||
// Initialize interface
|
||||
smart_interface::init();
|
||||
if (!smi())
|
||||
return 1;
|
||||
|
||||
// Parse input arguments
|
||||
const char *type = 0;
|
||||
ata_print_options ataopts;
|
||||
scsi_print_options scsiopts;
|
||||
nvme_print_options nvmeopts;
|
||||
bool print_type_only = false;
|
||||
{
|
||||
ataopts.smart_vendor_attrib = scsiopts.smart_vendor_attrib = nvmeopts.smart_vendor_attrib = true;
|
||||
}
|
||||
|
||||
// Store formatted current time for jout_startup_datetime()
|
||||
// Output as JSON regardless of '-i' option
|
||||
{
|
||||
time_t now = time(nullptr);
|
||||
dateandtimezoneepoch(startup_datetime_buf, now);
|
||||
jglb["local_time"] += {{"time_t", now}, {"asctime", startup_datetime_buf}};
|
||||
}
|
||||
|
||||
smart_device_auto_ptr dev;
|
||||
if (!strcmp(name, "-"))
|
||||
{
|
||||
// Parse "smartctl -r ataioctl,2 ..." output from stdin
|
||||
if (type || print_type_only)
|
||||
{
|
||||
pout("-d option is not allowed in conjunction with device name \"-\".\n");
|
||||
UsageSummary();
|
||||
return FAILCMD;
|
||||
}
|
||||
dev = get_parsed_ata_device(smi(), name);
|
||||
}
|
||||
else
|
||||
// get device of appropriate type
|
||||
dev = smi()->get_smart_device(name, type);
|
||||
if (!dev)
|
||||
{
|
||||
jerr("%s: %s\n", name, smi()->get_errmsg());
|
||||
if (type)
|
||||
printvalidarglistmessage('d');
|
||||
else
|
||||
pout("Please specify device type with the -d option.\n");
|
||||
UsageSummary();
|
||||
return FAILCMD;
|
||||
}
|
||||
|
||||
if (print_type_only)
|
||||
// Report result of first autodetection
|
||||
pout("%s: Device of type '%s' [%s] detected\n",
|
||||
dev->get_info_name(), dev->get_dev_type(), get_protocol_info(dev.get()));
|
||||
|
||||
if (dev->is_ata() && ataopts.powermode >= 2 && dev->is_powered_down())
|
||||
{
|
||||
jinf("Device is in STANDBY (OS) mode, exit(%d)\n", ataopts.powerexit);
|
||||
return ataopts.powerexit;
|
||||
}
|
||||
|
||||
// Open device
|
||||
{
|
||||
// Save old info
|
||||
smart_device::device_info oldinfo = dev->get_info();
|
||||
|
||||
// Open with autodetect support, may return 'better' device
|
||||
dev.replace(dev->autodetect_open());
|
||||
|
||||
// Report if type has changed
|
||||
if ((ata_debugmode || scsi_debugmode || nvme_debugmode || print_type_only) && oldinfo.dev_type != dev->get_dev_type())
|
||||
pout("%s: Device open changed type from '%s' to '%s'\n",
|
||||
dev->get_info_name(), oldinfo.dev_type.c_str(), dev->get_dev_type());
|
||||
}
|
||||
if (!dev->is_open())
|
||||
{
|
||||
jerr("Smartctl open device: %s failed: %s\n", dev->get_info_name(), dev->get_errmsg());
|
||||
return FAILDEV;
|
||||
}
|
||||
|
||||
// Add JSON info similar to --scan output
|
||||
js_device_info(jglb["device"], dev.get());
|
||||
|
||||
// now call appropriate ATA or SCSI routine
|
||||
int retval = 0;
|
||||
if (print_type_only)
|
||||
jout("%s: Device of type '%s' [%s] opened\n",
|
||||
dev->get_info_name(), dev->get_dev_type(), get_protocol_info(dev.get()));
|
||||
else if (dev->is_ata())
|
||||
retval = ataPrintMain(dev->to_ata(), ataopts);
|
||||
else if (dev->is_scsi())
|
||||
retval = scsiPrintMain(dev->to_scsi(), scsiopts);
|
||||
else if (dev->is_nvme())
|
||||
retval = nvmePrintMain(dev->to_nvme(), nvmeopts);
|
||||
else
|
||||
// we should never fall into this branch!
|
||||
pout("%s: Neither ATA, SCSI nor NVMe device\n", dev->get_info_name());
|
||||
|
||||
dev->close();
|
||||
return retval;
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
* smartctl.h
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2002-10 Bruce Allen
|
||||
* Copyright (C) 2008-21 Christian Franke
|
||||
* Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef SMARTCTL_H_
|
||||
#define SMARTCTL_H_
|
||||
|
||||
#define SMARTCTL_H_CVSID "$Id: smartctl.h 5200 2021-02-07 14:19:40Z chrfranke $\n"
|
||||
|
||||
// Return codes (bitmask)
|
||||
|
||||
// command line did not parse, or internal error occurred in smartctl
|
||||
#define FAILCMD (0x01 << 0)
|
||||
|
||||
// device open failed
|
||||
#define FAILDEV (0x01 << 1)
|
||||
|
||||
// device is in low power mode and -n option requests to exit
|
||||
#define FAILPOWER (0x01 << 1)
|
||||
|
||||
// read device identity (ATA only) failed
|
||||
#define FAILID (0x01 << 1)
|
||||
|
||||
// smart command failed, or ATA identify device structure missing information
|
||||
#define FAILSMART (0x01 << 2)
|
||||
|
||||
// SMART STATUS returned FAILURE
|
||||
#define FAILSTATUS (0x01 << 3)
|
||||
|
||||
// Attributes found <= threshold with prefail=1
|
||||
#define FAILATTR (0x01 << 4)
|
||||
|
||||
// SMART STATUS returned GOOD but age attributes failed or prefail
|
||||
// attributes have failed in the past
|
||||
#define FAILAGE (0x01 << 5)
|
||||
|
||||
// Device had Errors in the error log
|
||||
#define FAILERR (0x01 << 6)
|
||||
|
||||
// Device had Errors in the self-test log
|
||||
#define FAILLOG (0x01 << 7)
|
||||
|
||||
// Classes of SMART commands. Here 'mandatory' means "Required by the
|
||||
// ATA/ATAPI-5 Specification if the device implements the S.M.A.R.T.
|
||||
// command set." The 'mandatory' S.M.A.R.T. commands are: (1)
|
||||
// Enable/Disable Attribute Autosave, (2) Enable/Disable S.M.A.R.T.,
|
||||
// and (3) S.M.A.R.T. Return Status. All others are optional.
|
||||
enum failure_type
|
||||
{
|
||||
OPTIONAL_CMD,
|
||||
MANDATORY_CMD,
|
||||
};
|
||||
|
||||
// Globals to set failuretest() policy
|
||||
extern bool failuretest_conservative;
|
||||
extern unsigned char failuretest_permissive;
|
||||
|
||||
// Compares failure type to policy in effect, and either exits or
|
||||
// simply returns to the calling routine.
|
||||
void failuretest(failure_type type, int returnvalue);
|
||||
|
||||
#include <string>
|
||||
// Globals to control printing
|
||||
extern bool printing_is_switchable;
|
||||
extern bool printing_is_off;
|
||||
extern std::string nvmeTemp;
|
||||
extern std::string sataTemp;
|
||||
|
||||
// Printing control functions
|
||||
inline void print_on()
|
||||
{
|
||||
if (printing_is_switchable)
|
||||
printing_is_off = false;
|
||||
}
|
||||
inline void print_off()
|
||||
{
|
||||
if (printing_is_switchable)
|
||||
printing_is_off = true;
|
||||
}
|
||||
|
||||
// The singleton global JSON object
|
||||
#include "json.h"
|
||||
extern json jglb;
|
||||
|
||||
#include "utility.h" // __attribute_format_printf()
|
||||
// TODO: move this to a new include file?
|
||||
|
||||
// Version of pout() for items already included in JSON output
|
||||
void jout(const char *fmt, ...)
|
||||
__attribute_format_printf(1, 2);
|
||||
// Version of pout() for info/warning/error messages
|
||||
void jinf(const char *fmt, ...)
|
||||
__attribute_format_printf(1, 2);
|
||||
void jwrn(const char *fmt, ...)
|
||||
__attribute_format_printf(1, 2);
|
||||
void jerr(const char *fmt, ...)
|
||||
__attribute_format_printf(1, 2);
|
||||
|
||||
// Print smartctl start-up date and time and timezone
|
||||
void jout_startup_datetime(const char *prefix);
|
||||
int main_worker(const char *name);
|
||||
#endif
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* static_assert.h
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2019 Christian Franke
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef STATIC_ASSERT_H
|
||||
#define STATIC_ASSERT_H
|
||||
|
||||
#define STATIC_ASSERT_H_CVSID "$Id: static_assert.h 4934 2019-07-01 20:54:14Z chrfranke $"
|
||||
|
||||
#if __cplusplus >= 201103 || _MSVC_LANG >= 201103
|
||||
#define STATIC_ASSERT(x) static_assert((x), #x)
|
||||
#elif __STDC_VERSION__ >= 201112
|
||||
#define STATIC_ASSERT(x) _Static_assert((x), #x)
|
||||
#elif __GNUC__ >= 4
|
||||
#define STATIC_ASSERT(x) typedef char static_assertion[(x) ? 1 : -1] \
|
||||
__attribute__((unused))
|
||||
#else
|
||||
#define STATIC_ASSERT(x) typedef char static_assertion[(x) ? 1 : -1]
|
||||
#endif
|
||||
|
||||
#endif // STATIC_ASSERT_H
|
|
@ -1,937 +0,0 @@
|
|||
/*
|
||||
* utility.cpp
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2002-12 Bruce Allen
|
||||
* Copyright (C) 2008-22 Christian Franke
|
||||
* Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
// THIS FILE IS INTENDED FOR UTILITY ROUTINES THAT ARE APPLICABLE TO
|
||||
// BOTH SCSI AND ATA DEVICES, AND THAT MAY BE USED IN SMARTD,
|
||||
// SMARTCTL, OR BOTH.
|
||||
|
||||
#include "config.h"
|
||||
#define __STDC_FORMAT_MACROS 1 // enable PRI* for C++
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef HAVE_LOCALE_H
|
||||
#include <locale.h>
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#include <mbstring.h> // _mbsinc()
|
||||
#endif
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "utility.h"
|
||||
|
||||
#include "atacmds.h"
|
||||
#include "dev_interface.h"
|
||||
#include "sg_unaligned.h"
|
||||
|
||||
#ifndef USE_CLOCK_MONOTONIC
|
||||
#ifdef __MINGW32__
|
||||
// If MinGW-w64 < 9.0.0 or Windows < 8, GetSystemTimeAsFileTime() is used for
|
||||
// std::chrono::high_resolution_clock. This provides only 1/64s (>15ms) resolution.
|
||||
// CLOCK_MONOTONIC uses QueryPerformanceCounter() which provides <1us resolution.
|
||||
#define USE_CLOCK_MONOTONIC 1
|
||||
#else
|
||||
// Use std::chrono::high_resolution_clock.
|
||||
#include <chrono>
|
||||
#define USE_CLOCK_MONOTONIC 0
|
||||
#endif
|
||||
#endif // USE_CLOCK_MONOTONIC
|
||||
|
||||
const char *utility_cpp_cvsid = "$Id: utility.cpp 5297 2022-01-07 00:51:15Z dpgilbert $" UTILITY_H_CVSID;
|
||||
|
||||
const char *packet_types[] = {
|
||||
"Direct-access (disk)",
|
||||
"Sequential-access (tape)",
|
||||
"Printer",
|
||||
"Processor",
|
||||
"Write-once (optical disk)",
|
||||
"CD/DVD",
|
||||
"Scanner",
|
||||
"Optical memory (optical disk)",
|
||||
"Medium changer",
|
||||
"Communications",
|
||||
"Graphic arts pre-press (10)",
|
||||
"Graphic arts pre-press (11)",
|
||||
"Array controller",
|
||||
"Enclosure services",
|
||||
"Reduced block command (simplified disk)",
|
||||
"Optical card reader/writer"};
|
||||
|
||||
// BUILD_INFO can be provided by package maintainers
|
||||
#ifndef BUILD_INFO
|
||||
#define BUILD_INFO "(local build)"
|
||||
#endif
|
||||
|
||||
// Make version information string
|
||||
std::string format_version_info(const char *prog_name, bool full /*= false*/)
|
||||
{
|
||||
std::string info = strprintf(
|
||||
"%s " PACKAGE_VERSION " "
|
||||
#ifdef SMARTMONTOOLS_SVN_REV
|
||||
SMARTMONTOOLS_SVN_DATE " r" SMARTMONTOOLS_SVN_REV
|
||||
#else
|
||||
"(build date " __DATE__ ")" // checkout without expansion of Id keywords
|
||||
#endif
|
||||
" [%s] " BUILD_INFO "\n"
|
||||
"Copyright (C) 2002-22, Bruce Allen, Christian Franke, www.smartmontools.org\n",
|
||||
prog_name, smi()->get_os_version_str().c_str());
|
||||
if (!full)
|
||||
return info;
|
||||
|
||||
info += "\n";
|
||||
info += prog_name;
|
||||
info += " comes with ABSOLUTELY NO WARRANTY. This is free\n"
|
||||
"software, and you are welcome to redistribute it under\n"
|
||||
"the terms of the GNU General Public License; either\n"
|
||||
"version 2, or (at your option) any later version.\n"
|
||||
"See https://www.gnu.org for further details.\n"
|
||||
"\n"
|
||||
"smartmontools release " PACKAGE_VERSION
|
||||
" dated " SMARTMONTOOLS_RELEASE_DATE " at " SMARTMONTOOLS_RELEASE_TIME "\n"
|
||||
#ifdef SMARTMONTOOLS_SVN_REV
|
||||
"smartmontools SVN rev " SMARTMONTOOLS_SVN_REV
|
||||
" dated " SMARTMONTOOLS_SVN_DATE " at " SMARTMONTOOLS_SVN_TIME "\n"
|
||||
#else
|
||||
"smartmontools SVN rev is unknown\n"
|
||||
#endif
|
||||
"smartmontools build host: " SMARTMONTOOLS_BUILD_HOST "\n"
|
||||
"smartmontools build with: "
|
||||
|
||||
#define N2S_(s) #s
|
||||
#define N2S(s) "(" N2S_(s) ")"
|
||||
#if __cplusplus > 201703
|
||||
"C++2x" N2S(__cplusplus)
|
||||
#elif __cplusplus == 201703
|
||||
"C++17"
|
||||
#elif __cplusplus > 201402
|
||||
"C++14" N2S(__cplusplus)
|
||||
#elif __cplusplus == 201402
|
||||
"C++14"
|
||||
#elif __cplusplus > 201103
|
||||
"C++11" N2S(__cplusplus)
|
||||
#elif __cplusplus == 201103
|
||||
"C++11"
|
||||
#elif __cplusplus > 199711
|
||||
"C++98" N2S(__cplusplus)
|
||||
#elif __cplusplus == 199711
|
||||
"C++98"
|
||||
#else
|
||||
"C++" N2S(__cplusplus)
|
||||
#endif
|
||||
#undef N2S
|
||||
#undef N2S_
|
||||
|
||||
#if defined(__GNUC__) && defined(__VERSION__) // works also with CLang
|
||||
", GCC " __VERSION__
|
||||
#endif
|
||||
"\n"
|
||||
"smartmontools configure arguments:"
|
||||
#ifdef SOURCE_DATE_EPOCH
|
||||
" [hidden in reproducible builds]\n"
|
||||
"reproducible build SOURCE_DATE_EPOCH: "
|
||||
#endif
|
||||
;
|
||||
#ifdef SOURCE_DATE_EPOCH
|
||||
char ts[32];
|
||||
struct tm tmbuf;
|
||||
strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S", time_to_tm_local(&tmbuf, SOURCE_DATE_EPOCH));
|
||||
info += strprintf("%u (%s)", (unsigned)SOURCE_DATE_EPOCH, ts);
|
||||
#else
|
||||
info += (sizeof(SMARTMONTOOLS_CONFIGURE_ARGS) > 1 ? SMARTMONTOOLS_CONFIGURE_ARGS : " [no arguments given]");
|
||||
#endif
|
||||
info += '\n';
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
// Solaris only: Get site-default timezone. This is called from
|
||||
// UpdateTimezone() when TZ environment variable is unset at startup.
|
||||
#if defined(__SVR4) && defined(__sun)
|
||||
static const char *TIMEZONE_FILE = "/etc/TIMEZONE";
|
||||
|
||||
static char *ReadSiteDefaultTimezone()
|
||||
{
|
||||
FILE *fp;
|
||||
char buf[512], *tz;
|
||||
int n;
|
||||
|
||||
tz = NULL;
|
||||
fp = fopen(TIMEZONE_FILE, "r");
|
||||
if (fp == NULL)
|
||||
return NULL;
|
||||
while (fgets(buf, sizeof(buf), fp))
|
||||
{
|
||||
if (strncmp(buf, "TZ=", 3)) // searches last "TZ=" line
|
||||
continue;
|
||||
n = strlen(buf) - 1;
|
||||
if (buf[n] == '\n')
|
||||
buf[n] = 0;
|
||||
if (tz)
|
||||
free(tz);
|
||||
tz = strdup(buf);
|
||||
}
|
||||
fclose(fp);
|
||||
return tz;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Make sure that this executable is aware if the user has changed the
|
||||
// time-zone since the last time we polled devices. The canonical
|
||||
// example is a user who starts smartd on a laptop, then flies across
|
||||
// time-zones with a laptop, and then changes the timezone, WITHOUT
|
||||
// restarting smartd. This is a work-around for a bug in
|
||||
// GLIBC. Yuk. See bug number 48184 at http://bugs.debian.org and
|
||||
// thanks to Ian Redfern for posting a workaround.
|
||||
|
||||
// Please refer to the smartd manual page, in the section labeled LOG
|
||||
// TIMESTAMP TIMEZONE.
|
||||
void FixGlibcTimeZoneBug()
|
||||
{
|
||||
#if __GLIBC__
|
||||
if (!getenv("TZ"))
|
||||
{
|
||||
putenv((char *)"TZ=GMT"); // POSIX prototype is 'int putenv(char *)'
|
||||
tzset();
|
||||
putenv((char *)"TZ");
|
||||
tzset();
|
||||
}
|
||||
#elif _WIN32
|
||||
if (!getenv("TZ"))
|
||||
{
|
||||
putenv("TZ=GMT");
|
||||
tzset();
|
||||
putenv("TZ="); // empty value removes TZ, putenv("TZ") does nothing
|
||||
tzset();
|
||||
}
|
||||
#elif defined(__SVR4) && defined(__sun)
|
||||
// In Solaris, putenv("TZ=") sets null string and invalid timezone.
|
||||
// putenv("TZ") does nothing. With invalid TZ, tzset() do as if
|
||||
// TZ=GMT. With TZ unset, /etc/TIMEZONE will be read only _once_ at
|
||||
// first tzset() call. Conclusion: Unlike glibc, dynamic
|
||||
// configuration of timezone can be done only by changing actual
|
||||
// value of TZ environment value.
|
||||
enum tzstate
|
||||
{
|
||||
NOT_CALLED_YET,
|
||||
USER_TIMEZONE,
|
||||
TRACK_TIMEZONE
|
||||
};
|
||||
static enum tzstate state = NOT_CALLED_YET;
|
||||
|
||||
static struct stat prev_stat;
|
||||
static char *prev_tz;
|
||||
struct stat curr_stat;
|
||||
char *curr_tz;
|
||||
|
||||
if (state == NOT_CALLED_YET)
|
||||
{
|
||||
if (getenv("TZ"))
|
||||
{
|
||||
state = USER_TIMEZONE; // use supplied timezone
|
||||
}
|
||||
else
|
||||
{
|
||||
state = TRACK_TIMEZONE;
|
||||
if (stat(TIMEZONE_FILE, &prev_stat))
|
||||
{
|
||||
state = USER_TIMEZONE; // no TZ, no timezone file; use GMT forever
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_tz = ReadSiteDefaultTimezone(); // track timezone file change
|
||||
if (prev_tz)
|
||||
putenv(prev_tz);
|
||||
}
|
||||
}
|
||||
tzset();
|
||||
}
|
||||
else if (state == TRACK_TIMEZONE)
|
||||
{
|
||||
if (stat(TIMEZONE_FILE, &curr_stat) == 0 && (curr_stat.st_ctime != prev_stat.st_ctime || curr_stat.st_mtime != prev_stat.st_mtime))
|
||||
{
|
||||
// timezone file changed
|
||||
curr_tz = ReadSiteDefaultTimezone();
|
||||
if (curr_tz)
|
||||
{
|
||||
putenv(curr_tz);
|
||||
if (prev_tz)
|
||||
free(prev_tz);
|
||||
prev_tz = curr_tz;
|
||||
prev_stat = curr_stat;
|
||||
}
|
||||
}
|
||||
tzset();
|
||||
}
|
||||
#endif
|
||||
// OTHER OS/LIBRARY FIXES SHOULD GO HERE, IF DESIRED. PLEASE TRY TO
|
||||
// KEEP THEM INDEPENDENT.
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Fix strings in tzname[] to avoid long names with non-ascii characters.
|
||||
// If TZ is not set, tzset() in the MSVC runtime sets tzname[] to the
|
||||
// national language timezone names returned by GetTimezoneInformation().
|
||||
static char *fixtzname(char *dest, int destsize, const char *src)
|
||||
{
|
||||
int i = 0, j = 0;
|
||||
while (src[i] && j < destsize - 1)
|
||||
{
|
||||
int i2 = (const char *)_mbsinc((const unsigned char *)src + i) - src;
|
||||
if (i2 > i + 1)
|
||||
i = i2; // Ignore multibyte chars
|
||||
else
|
||||
{
|
||||
if ('A' <= src[i] && src[i] <= 'Z')
|
||||
dest[j++] = src[i]; // "Pacific Standard Time" => "PST"
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (j < 2)
|
||||
j = 0;
|
||||
dest[j] = 0;
|
||||
return dest;
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
// This value follows the peripheral device type value as defined in
|
||||
// SCSI Primary Commands, ANSI INCITS 301:1997. It is also used in
|
||||
// the ATA standard for packet devices to define the device type.
|
||||
const char *packetdevicetype(int type)
|
||||
{
|
||||
if (type < 0x10)
|
||||
return packet_types[type];
|
||||
|
||||
if (type < 0x20)
|
||||
return "Reserved";
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
// Convert time to broken-down local time, throw on error.
|
||||
struct tm *time_to_tm_local(struct tm *tp, time_t t)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
// POSIX (missing in MSVRCT, C and C++)
|
||||
if (!localtime_r(&t, tp))
|
||||
throw std::runtime_error("localtime_r() failed");
|
||||
#else
|
||||
// MSVCRT (missing in POSIX, C11 variant differs)
|
||||
if (localtime_s(tp, &t))
|
||||
throw std::runtime_error("localtime_s() failed");
|
||||
#endif
|
||||
return tp;
|
||||
}
|
||||
|
||||
// Utility function prints date and time and timezone into a character
|
||||
// buffer of length 64. All the fuss is needed to get the right
|
||||
// timezone info (sigh).
|
||||
void dateandtimezoneepoch(char (&buffer)[DATEANDEPOCHLEN], time_t tval)
|
||||
{
|
||||
FixGlibcTimeZoneBug();
|
||||
|
||||
// Get the time structure. We need this to determine if we are in
|
||||
// daylight savings time or not.
|
||||
struct tm tmbuf, *tmval = time_to_tm_local(&tmbuf, tval);
|
||||
|
||||
// Convert to an ASCII string, put in datebuffer.
|
||||
// Same as: strftime(datebuffer, sizeof(datebuffer), "%a %b %e %H:%M:%S %Y\n"),
|
||||
// but always in "C" locale.
|
||||
char datebuffer[32];
|
||||
STATIC_ASSERT(sizeof(datebuffer) >= 26); // assumed by asctime_r()
|
||||
#ifndef _WIN32
|
||||
// POSIX (missing in MSVRCT, C and C++)
|
||||
if (!asctime_r(tmval, datebuffer))
|
||||
throw std::runtime_error("asctime_r() failed");
|
||||
#else
|
||||
// MSVCRT, C11 (missing in POSIX)
|
||||
if (asctime_s(datebuffer, sizeof(datebuffer), tmval))
|
||||
throw std::runtime_error("asctime_s() failed");
|
||||
#endif
|
||||
|
||||
// Remove newline
|
||||
int lenm1 = strlen(datebuffer) - 1;
|
||||
datebuffer[lenm1 >= 0 ? lenm1 : 0] = '\0';
|
||||
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
// tzname is missing in MSVC14
|
||||
#define tzname _tzname
|
||||
#endif
|
||||
|
||||
// correct timezone name
|
||||
const char *timezonename;
|
||||
if (tmval->tm_isdst == 0)
|
||||
// standard time zone
|
||||
timezonename = tzname[0];
|
||||
else if (tmval->tm_isdst > 0)
|
||||
// daylight savings in effect
|
||||
timezonename = tzname[1];
|
||||
else
|
||||
// unable to determine if daylight savings in effect
|
||||
timezonename = "";
|
||||
|
||||
#ifdef _WIN32
|
||||
// Fix long non-ascii timezone names
|
||||
// cppcheck-suppress variableScope
|
||||
char tzfixbuf[6 + 1] = "";
|
||||
if (!getenv("TZ"))
|
||||
timezonename = fixtzname(tzfixbuf, sizeof(tzfixbuf), timezonename);
|
||||
#endif
|
||||
|
||||
// Finally put the information into the buffer as needed.
|
||||
snprintf(buffer, DATEANDEPOCHLEN, "%s %s", datebuffer, timezonename);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// A replacement for perror() that sends output to our choice of
|
||||
// printing. If errno not set then just print message.
|
||||
void syserror(const char *message)
|
||||
{
|
||||
|
||||
if (errno)
|
||||
{
|
||||
// Get the correct system error message:
|
||||
const char *errormessage = strerror(errno);
|
||||
|
||||
// Check that caller has handed a sensible string, and provide
|
||||
// appropriate output. See perrror(3) man page to understand better.
|
||||
if (message && *message)
|
||||
pout("%s: %s\n", message, errormessage);
|
||||
else
|
||||
pout("%s\n", errormessage);
|
||||
}
|
||||
else if (message && *message)
|
||||
pout("%s\n", message);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Check regular expression for non-portable features.
|
||||
//
|
||||
// POSIX extended regular expressions interpret unmatched ')' ordinary:
|
||||
// "The close-parenthesis shall be considered special in this context
|
||||
// only if matched with a preceding open-parenthesis."
|
||||
//
|
||||
// GNU libc and BSD libc support unmatched ')', Cygwin reports an error.
|
||||
//
|
||||
// POSIX extended regular expressions do not define empty subexpressions:
|
||||
// "A vertical-line appearing first or last in an ERE, or immediately following
|
||||
// a vertical-line or a left-parenthesis, or immediately preceding a
|
||||
// right-parenthesis, produces undefined results."
|
||||
//
|
||||
// GNU libc and Cygwin support empty subexpressions, BSD libc reports an error.
|
||||
//
|
||||
static const char *check_regex(const char *pattern)
|
||||
{
|
||||
int level = 0;
|
||||
char c;
|
||||
|
||||
for (int i = 0; (c = pattern[i]); i++)
|
||||
{
|
||||
// Skip "\x"
|
||||
if (c == '\\')
|
||||
{
|
||||
if (!pattern[++i])
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip "[...]"
|
||||
if (c == '[')
|
||||
{
|
||||
if (pattern[++i] == '^')
|
||||
i++;
|
||||
if (!pattern[i++])
|
||||
break;
|
||||
while ((c = pattern[i]) && c != ']')
|
||||
i++;
|
||||
if (!c)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check "(...)" nesting
|
||||
if (c == '(')
|
||||
level++;
|
||||
else if (c == ')' && --level < 0)
|
||||
return "Unmatched ')'";
|
||||
|
||||
// Check for leading/trailing '|' or "||", "|)", "|$", "(|", "^|"
|
||||
char c1;
|
||||
if ((c == '|' && (i == 0 || !(c1 = pattern[i + 1]) || c1 == '|' || c1 == ')' || c1 == '$')) || ((c == '(' || c == '^') && pattern[i + 1] == '|'))
|
||||
return "Empty '|' subexpression";
|
||||
}
|
||||
|
||||
return (const char *)0;
|
||||
}
|
||||
|
||||
// Wrapper class for POSIX regex(3) or std::regex
|
||||
|
||||
#ifndef WITH_CXX11_REGEX
|
||||
|
||||
regular_expression::regular_expression()
|
||||
{
|
||||
memset(&m_regex_buf, 0, sizeof(m_regex_buf));
|
||||
}
|
||||
|
||||
regular_expression::~regular_expression()
|
||||
{
|
||||
free_buf();
|
||||
}
|
||||
|
||||
regular_expression::regular_expression(const regular_expression &x)
|
||||
: m_pattern(x.m_pattern),
|
||||
m_errmsg(x.m_errmsg)
|
||||
{
|
||||
memset(&m_regex_buf, 0, sizeof(m_regex_buf));
|
||||
copy_buf(x);
|
||||
}
|
||||
|
||||
regular_expression ®ular_expression::operator=(const regular_expression &x)
|
||||
{
|
||||
m_pattern = x.m_pattern;
|
||||
m_errmsg = x.m_errmsg;
|
||||
free_buf();
|
||||
copy_buf(x);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void regular_expression::free_buf()
|
||||
{
|
||||
if (nonempty(&m_regex_buf, sizeof(m_regex_buf)))
|
||||
{
|
||||
regfree(&m_regex_buf);
|
||||
memset(&m_regex_buf, 0, sizeof(m_regex_buf));
|
||||
}
|
||||
}
|
||||
|
||||
void regular_expression::copy_buf(const regular_expression &x)
|
||||
{
|
||||
if (nonempty(&x.m_regex_buf, sizeof(x.m_regex_buf)))
|
||||
{
|
||||
// There is no POSIX compiled-regex-copy command.
|
||||
if (!compile())
|
||||
throw std::runtime_error(strprintf(
|
||||
"Unable to recompile regular expression \"%s\": %s",
|
||||
m_pattern.c_str(), m_errmsg.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !WITH_CXX11_REGEX
|
||||
|
||||
regular_expression::regular_expression(const char *pattern)
|
||||
: m_pattern(pattern)
|
||||
{
|
||||
if (!compile())
|
||||
throw std::runtime_error(strprintf(
|
||||
"error in regular expression \"%s\": %s",
|
||||
m_pattern.c_str(), m_errmsg.c_str()));
|
||||
}
|
||||
|
||||
bool regular_expression::compile(const char *pattern)
|
||||
{
|
||||
#ifndef WITH_CXX11_REGEX
|
||||
free_buf();
|
||||
#endif
|
||||
m_pattern = pattern;
|
||||
return compile();
|
||||
}
|
||||
|
||||
bool regular_expression::compile()
|
||||
{
|
||||
#ifdef WITH_CXX11_REGEX
|
||||
try
|
||||
{
|
||||
m_regex.assign(m_pattern, std::regex_constants::extended);
|
||||
}
|
||||
catch (std::regex_error &ex)
|
||||
{
|
||||
m_errmsg = ex.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
int errcode = regcomp(&m_regex_buf, m_pattern.c_str(), REG_EXTENDED);
|
||||
if (errcode)
|
||||
{
|
||||
char errmsg[512];
|
||||
regerror(errcode, &m_regex_buf, errmsg, sizeof(errmsg));
|
||||
m_errmsg = errmsg;
|
||||
free_buf();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char *errmsg = check_regex(m_pattern.c_str());
|
||||
if (errmsg)
|
||||
{
|
||||
m_errmsg = errmsg;
|
||||
#ifdef WITH_CXX11_REGEX
|
||||
m_regex = std::regex();
|
||||
#else
|
||||
free_buf();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
m_errmsg.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool regular_expression::full_match(const char *str) const
|
||||
{
|
||||
#ifdef WITH_CXX11_REGEX
|
||||
return std::regex_match(str, m_regex);
|
||||
#else
|
||||
match_range range;
|
||||
return (!regexec(&m_regex_buf, str, 1, &range, 0) && range.rm_so == 0 && range.rm_eo == (int)strlen(str));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool regular_expression::execute(const char *str, unsigned nmatch, match_range *pmatch) const
|
||||
{
|
||||
#ifdef WITH_CXX11_REGEX
|
||||
std::cmatch m;
|
||||
if (!std::regex_search(str, m, m_regex))
|
||||
return false;
|
||||
unsigned sz = m.size();
|
||||
for (unsigned i = 0; i < nmatch; i++)
|
||||
{
|
||||
if (i < sz && *m[i].first)
|
||||
{
|
||||
pmatch[i].rm_so = m[i].first - str;
|
||||
pmatch[i].rm_eo = m[i].second - str;
|
||||
}
|
||||
else
|
||||
pmatch[i].rm_so = pmatch[i].rm_eo = -1;
|
||||
}
|
||||
return true;
|
||||
|
||||
#else
|
||||
return !regexec(&m_regex_buf, str, nmatch, pmatch, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Splits an argument to the -t option that is assumed to be of the form
|
||||
// "selective,%lld-%lld" (prefixes of "0" (for octal) and "0x"/"0X" (for hex)
|
||||
// are allowed). The first long long int is assigned to *start and the second
|
||||
// to *stop. Returns zero if successful and non-zero otherwise.
|
||||
int split_selective_arg(char *s, uint64_t *start,
|
||||
uint64_t *stop, int *mode)
|
||||
{
|
||||
char *tailptr;
|
||||
if (!(s = strchr(s, ',')))
|
||||
return 1;
|
||||
bool add = false;
|
||||
if (!isdigit((int)(*++s)))
|
||||
{
|
||||
*start = *stop = 0;
|
||||
if (!strncmp(s, "redo", 4))
|
||||
*mode = SEL_REDO;
|
||||
else if (!strncmp(s, "next", 4))
|
||||
*mode = SEL_NEXT;
|
||||
else if (!strncmp(s, "cont", 4))
|
||||
*mode = SEL_CONT;
|
||||
else
|
||||
return 1;
|
||||
s += 4;
|
||||
if (!*s)
|
||||
return 0;
|
||||
if (*s != '+')
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*mode = SEL_RANGE;
|
||||
errno = 0;
|
||||
// Last argument to strtoull (the base) is 0 meaning that decimal is assumed
|
||||
// unless prefixes of "0" (for octal) or "0x"/"0X" (for hex) are used.
|
||||
*start = strtoull(s, &tailptr, 0);
|
||||
s = tailptr;
|
||||
add = (*s == '+');
|
||||
if (!(!errno && (add || *s == '-')))
|
||||
return 1;
|
||||
if (!strcmp(s, "-max"))
|
||||
{
|
||||
*stop = ~(uint64_t)0; // replaced by max LBA later
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
*stop = strtoull(s + 1, &tailptr, 0);
|
||||
if (errno || *tailptr != '\0')
|
||||
return 1;
|
||||
if (add)
|
||||
{
|
||||
if (*stop > 0)
|
||||
(*stop)--;
|
||||
*stop += *start; // -t select,N+M => -t select,N,(N+M-1)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns true if region of memory contains non-zero entries
|
||||
bool nonempty(const void *data, int size)
|
||||
{
|
||||
for (int i = 0; i < size; i++)
|
||||
if (((const unsigned char *)data)[i])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy not null terminated char array to null terminated string.
|
||||
// Replace non-ascii characters. Remove leading and trailing blanks.
|
||||
const char *format_char_array(char *str, int strsize, const 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;
|
||||
}
|
||||
|
||||
// Format integer with thousands separator
|
||||
const char *format_with_thousands_sep(char *str, int strsize, uint64_t val,
|
||||
const char *thousands_sep /* = 0 */)
|
||||
{
|
||||
if (!thousands_sep)
|
||||
{
|
||||
thousands_sep = ",";
|
||||
#ifdef HAVE_LOCALE_H
|
||||
setlocale(LC_ALL, "");
|
||||
const struct lconv *currentlocale = localeconv();
|
||||
if (*(currentlocale->thousands_sep))
|
||||
thousands_sep = currentlocale->thousands_sep;
|
||||
#endif
|
||||
}
|
||||
|
||||
char num[64];
|
||||
snprintf(num, sizeof(num), "%" PRIu64, val);
|
||||
int numlen = strlen(num);
|
||||
|
||||
int i = 0, j = 0;
|
||||
do
|
||||
str[j++] = num[i++];
|
||||
while (i < numlen && (numlen - i) % 3 != 0 && j < strsize - 1);
|
||||
str[j] = 0;
|
||||
|
||||
while (i < numlen && j < strsize - 1)
|
||||
{
|
||||
j += snprintf(str + j, strsize - j, "%s%.3s", thousands_sep, num + i);
|
||||
i += 3;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
// Format capacity with SI prefixes
|
||||
const char *format_capacity(char *str, int strsize, uint64_t val,
|
||||
const char *decimal_point /* = 0 */)
|
||||
{
|
||||
if (!decimal_point)
|
||||
{
|
||||
decimal_point = ".";
|
||||
#ifdef HAVE_LOCALE_H
|
||||
setlocale(LC_ALL, "");
|
||||
const struct lconv *currentlocale = localeconv();
|
||||
if (*(currentlocale->decimal_point))
|
||||
decimal_point = currentlocale->decimal_point;
|
||||
#endif
|
||||
}
|
||||
|
||||
const unsigned factor = 1000; // 1024 for KiB,MiB,...
|
||||
static const char prefixes[] = " KMGTP";
|
||||
|
||||
// Find d with val in [d, d*factor)
|
||||
unsigned i = 0;
|
||||
uint64_t d = 1;
|
||||
for (uint64_t d2 = d * factor; val >= d2; d2 *= factor)
|
||||
{
|
||||
d = d2;
|
||||
if (++i >= sizeof(prefixes) - 2)
|
||||
break;
|
||||
}
|
||||
|
||||
// Print 3 digits
|
||||
uint64_t n = val / d;
|
||||
if (i == 0)
|
||||
snprintf(str, strsize, "%u B", (unsigned)n);
|
||||
else if (n >= 100) // "123 xB"
|
||||
snprintf(str, strsize, "%" PRIu64 " %cB", n, prefixes[i]);
|
||||
else if (n >= 10) // "12.3 xB"
|
||||
snprintf(str, strsize, "%" PRIu64 "%s%u %cB", n, decimal_point,
|
||||
(unsigned)(((val % d) * 10) / d), prefixes[i]);
|
||||
else // "1.23 xB"
|
||||
snprintf(str, strsize, "%" PRIu64 "%s%02u %cB", n, decimal_point,
|
||||
(unsigned)(((val % d) * 100) / d), prefixes[i]);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
// return (v)sprintf() formatted std::string
|
||||
__attribute_format_printf(1, 0)
|
||||
std::string vstrprintf(const char *fmt, va_list ap)
|
||||
{
|
||||
char buf[512];
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
buf[sizeof(buf) - 1] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::string strprintf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
std::string str = vstrprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
return str;
|
||||
}
|
||||
|
||||
#if defined(HAVE___INT128)
|
||||
// Compiler supports '__int128'.
|
||||
|
||||
// Recursive 128-bit to string conversion function
|
||||
static int snprint_uint128(char *str, int strsize, unsigned __int128 value)
|
||||
{
|
||||
if (strsize <= 0)
|
||||
return -1;
|
||||
|
||||
if (value <= 0xffffffffffffffffULL)
|
||||
{
|
||||
// Print leading digits as 64-bit value
|
||||
return snprintf(str, (size_t)strsize, "%" PRIu64, (uint64_t)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Recurse to print leading digits
|
||||
const uint64_t e19 = 10000000000000000000ULL; // 2^63 < 10^19 < 2^64
|
||||
int len1 = snprint_uint128(str, strsize, value / e19);
|
||||
if (len1 < 0)
|
||||
return -1;
|
||||
|
||||
// Print 19 digits remainder as 64-bit value
|
||||
int len2 = snprintf(str + (len1 < strsize ? len1 : strsize - 1),
|
||||
(size_t)(len1 < strsize ? strsize - len1 : 1),
|
||||
"%019" PRIu64, (uint64_t)(value % e19));
|
||||
if (len2 < 0)
|
||||
return -1;
|
||||
return len1 + len2;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert 128-bit unsigned integer provided as two 64-bit halves to a string.
|
||||
const char *uint128_hilo_to_str(char *str, int strsize, uint64_t value_hi, uint64_t value_lo)
|
||||
{
|
||||
snprint_uint128(str, strsize, ((unsigned __int128)value_hi << 64) | value_lo);
|
||||
return str;
|
||||
}
|
||||
|
||||
#elif defined(HAVE_LONG_DOUBLE_WIDER_PRINTF)
|
||||
// Compiler and *printf() support 'long double' which is wider than 'double'.
|
||||
|
||||
const char *uint128_hilo_to_str(char *str, int strsize, uint64_t value_hi, uint64_t value_lo)
|
||||
{
|
||||
snprintf(str, strsize, "%.0Lf", value_hi * (0xffffffffffffffffULL + 1.0L) + value_lo);
|
||||
return str;
|
||||
}
|
||||
|
||||
#else // !HAVE_LONG_DOUBLE_WIDER_PRINTF
|
||||
// No '__int128' or 'long double' support, use 'double'.
|
||||
|
||||
const char *uint128_hilo_to_str(char *str, int strsize, uint64_t value_hi, uint64_t value_lo)
|
||||
{
|
||||
snprintf(str, strsize, "%.0f", value_hi * (0xffffffffffffffffULL + 1.0) + value_lo);
|
||||
return str;
|
||||
}
|
||||
|
||||
#endif // HAVE___INT128
|
||||
|
||||
// Get microseconds since some unspecified starting point.
|
||||
long long get_timer_usec()
|
||||
{
|
||||
#if USE_CLOCK_MONOTONIC
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts))
|
||||
return -1;
|
||||
return ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
|
||||
#else
|
||||
return std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::high_resolution_clock::now().time_since_epoch())
|
||||
.count();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Runtime check of byte ordering, throws on error.
|
||||
static void check_endianness()
|
||||
{
|
||||
const union
|
||||
{
|
||||
// Force compile error if int type is not 32bit.
|
||||
unsigned char c[sizeof(int) == 4 ? 8 : -1];
|
||||
uint64_t i;
|
||||
} x = {{1, 2, 3, 4, 5, 6, 7, 8}};
|
||||
const uint64_t le = 0x0807060504030201ULL;
|
||||
const uint64_t be = 0x0102030405060708ULL;
|
||||
|
||||
if (!(x.i == (isbigendian() ? be : le) && sg_get_unaligned_le16(x.c) == (uint16_t)le && sg_get_unaligned_be16(x.c + 6) == (uint16_t)be && sg_get_unaligned_le32(x.c) == (uint32_t)le && sg_get_unaligned_be32(x.c + 4) == (uint32_t)be && sg_get_unaligned_le64(x.c) == le && sg_get_unaligned_be64(x.c) == be))
|
||||
throw std::logic_error("CPU endianness does not match compile time test");
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 7)
|
||||
|
||||
// G++ 7+: Assume sane implementation and avoid -Wformat-truncation warning
|
||||
static void check_snprintf() {}
|
||||
|
||||
#else
|
||||
|
||||
static void check_snprintf()
|
||||
{
|
||||
char buf[] = "ABCDEFGHI";
|
||||
int n1 = snprintf(buf, 8, "123456789");
|
||||
int n2 = snprintf(buf, 0, "X");
|
||||
if (!(!strcmp(buf, "1234567") && n1 == 9 && n2 == 1))
|
||||
throw std::logic_error("Function snprintf() does not conform to C99");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Runtime check of ./configure result, throws on error.
|
||||
void check_config()
|
||||
{
|
||||
check_endianness();
|
||||
check_snprintf();
|
||||
}
|
|
@ -1,369 +0,0 @@
|
|||
/*
|
||||
* utility.h
|
||||
*
|
||||
* Home page of code is: https://www.smartmontools.org
|
||||
*
|
||||
* Copyright (C) 2002-11 Bruce Allen
|
||||
* Copyright (C) 2008-21 Christian Franke
|
||||
* Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef UTILITY_H_
|
||||
#define UTILITY_H_
|
||||
|
||||
#define UTILITY_H_CVSID "$Id: utility.h 5297 2022-01-07 00:51:15Z dpgilbert $"
|
||||
|
||||
#include <float.h> // *DBL_MANT_DIG
|
||||
#include <time.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
#include <sys/types.h> // for regex.h (according to POSIX)
|
||||
#ifdef WITH_CXX11_REGEX
|
||||
#include <regex>
|
||||
#else
|
||||
#include <regex.h>
|
||||
#endif
|
||||
|
||||
#ifndef __GNUC__
|
||||
#define __attribute_format_printf(x, y) /**/
|
||||
#elif defined(__MINGW32__) && __USE_MINGW_ANSI_STDIO
|
||||
// Check format of __mingw_*printf() instead of MSVCRT.DLL:*printf()
|
||||
#define __attribute_format_printf(x, y) __attribute__((format(gnu_printf, x, y)))
|
||||
#else
|
||||
#define __attribute_format_printf(x, y) __attribute__((format(printf, x, y)))
|
||||
#endif
|
||||
|
||||
// Make version information string
|
||||
std::string format_version_info(const char *prog_name, bool full = false);
|
||||
|
||||
// return (v)sprintf() formatted std::string
|
||||
std::string strprintf(const char *fmt, ...)
|
||||
__attribute_format_printf(1, 2);
|
||||
std::string vstrprintf(const char *fmt, va_list ap);
|
||||
|
||||
// Return true if STR starts with PREFIX
|
||||
inline bool str_starts_with(const char *str, const char *prefix)
|
||||
{
|
||||
return !strncmp(str, prefix, strlen(prefix));
|
||||
}
|
||||
|
||||
inline bool str_starts_with(const std::string &str, const char *prefix)
|
||||
{
|
||||
return !strncmp(str.c_str(), prefix, strlen(prefix));
|
||||
}
|
||||
|
||||
// Convert time to broken-down local time, throw on error.
|
||||
struct tm *time_to_tm_local(struct tm *tp, time_t t);
|
||||
|
||||
// Utility function prints date and time and timezone into a character
|
||||
// buffer of length 64. All the fuss is needed to get the
|
||||
// right timezone info (sigh).
|
||||
#define DATEANDEPOCHLEN 64
|
||||
void dateandtimezoneepoch(char (&buffer)[DATEANDEPOCHLEN], time_t tval);
|
||||
|
||||
// like printf() except that we can control it better. Note --
|
||||
// although the prototype is given here in utility.h, the function
|
||||
// itself is defined differently in smartctl and smartd. So the
|
||||
// function definition(s) are in smartd.c and in smartctl.c.
|
||||
void pout(const char *fmt, ...)
|
||||
__attribute_format_printf(1, 2);
|
||||
|
||||
// replacement for perror() with redirected output.
|
||||
void syserror(const char *message);
|
||||
|
||||
// Function for processing -t selective... option in smartctl
|
||||
int split_selective_arg(char *s, uint64_t *start, uint64_t *stop, int *mode);
|
||||
|
||||
// Compile time check of byte ordering
|
||||
// (inline const function allows compiler to remove dead code)
|
||||
inline bool isbigendian()
|
||||
{
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void swap2(char *location);
|
||||
void swap4(char *location);
|
||||
void swap8(char *location);
|
||||
// Typesafe variants using overloading
|
||||
inline void swapx(unsigned short *p)
|
||||
{
|
||||
swap2((char *)p);
|
||||
}
|
||||
inline void swapx(unsigned int *p)
|
||||
{
|
||||
swap4((char *)p);
|
||||
}
|
||||
inline void swapx(uint64_t *p)
|
||||
{
|
||||
swap8((char *)p);
|
||||
}
|
||||
|
||||
// Runtime check of ./configure result, throws on error.
|
||||
void check_config();
|
||||
|
||||
// This value follows the peripheral device type value as defined in
|
||||
// SCSI Primary Commands, ANSI INCITS 301:1997. It is also used in
|
||||
// the ATA standard for packet devices to define the device type.
|
||||
const char *packetdevicetype(int type);
|
||||
|
||||
// returns true if any of the n bytes are nonzero, else zero.
|
||||
bool nonempty(const void *data, int size);
|
||||
|
||||
// needed to fix glibc bug
|
||||
void FixGlibcTimeZoneBug();
|
||||
|
||||
// Copy not null terminated char array to null terminated string.
|
||||
// Replace non-ascii characters. Remove leading and trailing blanks.
|
||||
const char *format_char_array(char *str, int strsize, const char *chr, int chrsize);
|
||||
|
||||
// Version for fixed size buffers.
|
||||
template <size_t STRSIZE, size_t CHRSIZE>
|
||||
inline const char *format_char_array(char (&str)[STRSIZE], const char (&chr)[CHRSIZE])
|
||||
{
|
||||
return format_char_array(str, (int)STRSIZE, chr, (int)CHRSIZE);
|
||||
}
|
||||
|
||||
// Format integer with thousands separator
|
||||
const char *format_with_thousands_sep(char *str, int strsize, uint64_t val,
|
||||
const char *thousands_sep = 0);
|
||||
|
||||
// Format capacity with SI prefixes
|
||||
const char *format_capacity(char *str, int strsize, uint64_t val,
|
||||
const char *decimal_point = 0);
|
||||
|
||||
// Wrapper class for a raw data buffer
|
||||
class raw_buffer
|
||||
{
|
||||
public:
|
||||
explicit raw_buffer(unsigned sz, unsigned char val = 0)
|
||||
: m_data(new unsigned char[sz]),
|
||||
m_size(sz)
|
||||
{
|
||||
memset(m_data, val, m_size);
|
||||
}
|
||||
|
||||
~raw_buffer()
|
||||
{
|
||||
delete[] m_data;
|
||||
}
|
||||
|
||||
unsigned size() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
unsigned char *data()
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
const unsigned char *data() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned char *m_data;
|
||||
unsigned m_size;
|
||||
|
||||
raw_buffer(const raw_buffer &);
|
||||
void operator=(const raw_buffer &);
|
||||
};
|
||||
|
||||
/// Wrapper class for FILE *.
|
||||
class stdio_file
|
||||
{
|
||||
public:
|
||||
explicit stdio_file(FILE *f = 0, bool owner = false)
|
||||
: m_file(f), m_owner(owner) {}
|
||||
|
||||
stdio_file(const char *name, const char *mode)
|
||||
: m_file(fopen(name, mode)), m_owner(true) {}
|
||||
|
||||
~stdio_file()
|
||||
{
|
||||
if (m_file && m_owner)
|
||||
fclose(m_file);
|
||||
}
|
||||
|
||||
bool open(const char *name, const char *mode)
|
||||
{
|
||||
if (m_file && m_owner)
|
||||
fclose(m_file);
|
||||
m_file = fopen(name, mode);
|
||||
m_owner = true;
|
||||
return !!m_file;
|
||||
}
|
||||
|
||||
void open(FILE *f, bool owner = false)
|
||||
{
|
||||
if (m_file && m_owner)
|
||||
fclose(m_file);
|
||||
m_file = f;
|
||||
m_owner = owner;
|
||||
}
|
||||
|
||||
bool close()
|
||||
{
|
||||
if (!m_file)
|
||||
return true;
|
||||
bool ok = !ferror(m_file);
|
||||
if (fclose(m_file))
|
||||
ok = false;
|
||||
m_file = 0;
|
||||
return ok;
|
||||
}
|
||||
|
||||
operator FILE *()
|
||||
{
|
||||
return m_file;
|
||||
}
|
||||
|
||||
bool operator!() const
|
||||
{
|
||||
return !m_file;
|
||||
}
|
||||
|
||||
private:
|
||||
FILE *m_file;
|
||||
bool m_owner;
|
||||
|
||||
stdio_file(const stdio_file &);
|
||||
void operator=(const stdio_file &);
|
||||
};
|
||||
|
||||
/// Wrapper class for POSIX regex(3) or std::regex
|
||||
/// Supports copy & assignment and is compatible with STL containers.
|
||||
class regular_expression
|
||||
{
|
||||
public:
|
||||
// Construction & assignment
|
||||
#ifdef WITH_CXX11_REGEX
|
||||
regular_expression() = default;
|
||||
|
||||
#else
|
||||
regular_expression();
|
||||
|
||||
~regular_expression();
|
||||
|
||||
regular_expression(const regular_expression &x);
|
||||
|
||||
regular_expression &operator=(const regular_expression &x);
|
||||
#endif
|
||||
|
||||
/// Construct with pattern, throw on error.
|
||||
explicit regular_expression(const char *pattern);
|
||||
|
||||
/// Set and compile new pattern, return false on error.
|
||||
bool compile(const char *pattern);
|
||||
|
||||
// Get pattern from last compile().
|
||||
const char *get_pattern() const
|
||||
{
|
||||
return m_pattern.c_str();
|
||||
}
|
||||
|
||||
/// Get error message from last compile().
|
||||
const char *get_errmsg() const
|
||||
{
|
||||
return m_errmsg.c_str();
|
||||
}
|
||||
|
||||
// Return true if pattern is not set or bad.
|
||||
bool empty() const
|
||||
{
|
||||
return (m_pattern.empty() || !m_errmsg.empty());
|
||||
}
|
||||
|
||||
/// Return true if full string matches pattern
|
||||
bool full_match(const char *str) const;
|
||||
|
||||
#ifdef WITH_CXX11_REGEX
|
||||
struct match_range
|
||||
{
|
||||
int rm_so, rm_eo;
|
||||
};
|
||||
#else
|
||||
typedef regmatch_t match_range;
|
||||
#endif
|
||||
|
||||
/// Return true if substring matches pattern, fill match_range array.
|
||||
bool execute(const char *str, unsigned nmatch, match_range *pmatch) const;
|
||||
|
||||
private:
|
||||
std::string m_pattern;
|
||||
std::string m_errmsg;
|
||||
|
||||
#ifdef WITH_CXX11_REGEX
|
||||
std::regex m_regex;
|
||||
#else
|
||||
regex_t m_regex_buf;
|
||||
void free_buf();
|
||||
void copy_buf(const regular_expression &x);
|
||||
#endif
|
||||
|
||||
bool compile();
|
||||
};
|
||||
|
||||
// 128-bit unsigned integer to string conversion.
|
||||
// Provides full integer precision if compiler supports '__int128'.
|
||||
// Otherwise precision depends on supported floating point data types.
|
||||
|
||||
#if defined(HAVE_LONG_DOUBLE_WIDER) && \
|
||||
(!defined(__MINGW32__) || defined(__USE_MINGW_ANSI_STDIO))
|
||||
// MinGW 'long double' type does not work with MSVCRT *printf()
|
||||
#define HAVE_LONG_DOUBLE_WIDER_PRINTF 1
|
||||
#else
|
||||
#undef HAVE_LONG_DOUBLE_WIDER_PRINTF
|
||||
#endif
|
||||
|
||||
// Return #bits precision provided by uint128_hilo_to_str().
|
||||
inline int uint128_to_str_precision_bits()
|
||||
{
|
||||
#if defined(HAVE___INT128)
|
||||
return 128;
|
||||
#elif defined(HAVE_LONG_DOUBLE_WIDER_PRINTF)
|
||||
return LDBL_MANT_DIG;
|
||||
#else
|
||||
return DBL_MANT_DIG;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Convert 128-bit unsigned integer provided as two 64-bit halves to a string.
|
||||
const char *uint128_hilo_to_str(char *str, int strsize, uint64_t value_hi, uint64_t value_lo);
|
||||
|
||||
// Version for fixed size buffers.
|
||||
template <size_t SIZE>
|
||||
inline const char *uint128_hilo_to_str(char (&str)[SIZE], uint64_t value_hi, uint64_t value_lo)
|
||||
{
|
||||
return uint128_hilo_to_str(str, (int)SIZE, value_hi, value_lo);
|
||||
}
|
||||
|
||||
/// Get microseconds since some unspecified starting point.
|
||||
/// Used only for command duration measurements in debug outputs.
|
||||
/// Returns -1 if unsupported.
|
||||
long long get_timer_usec();
|
||||
|
||||
#ifdef _WIN32
|
||||
// Get exe directory
|
||||
//(implemented in os_win32.cpp)
|
||||
std::string get_exe_dir();
|
||||
#endif
|
||||
|
||||
#ifdef OLD_INTERFACE
|
||||
// remaining controller types in old interface modules
|
||||
#define CONTROLLER_UNKNOWN 0x00
|
||||
#define CONTROLLER_ATA 0x01
|
||||
#define CONTROLLER_SCSI 0x02
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -12,5 +12,6 @@ int main(int argc, char *argv[])
|
|||
printf("cpuTemp: %f\n", kdk_real_get_cpu_temperature());
|
||||
printf("diskTemp : %d\n", kdk_real_get_disk_temperature(argv[argc - 1]));
|
||||
printf("diskRate : %d\n", kdk_real_get_disk_rate(argv[argc -1]));
|
||||
printf("ifnetSpeed : %f\n", kdk_real_get_if_speed(argv[argc - 2]));
|
||||
return 0;
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
#include "stdio.h"
|
||||
#include "../libkyrealtimeinfo.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
RealTimeInfo info;
|
||||
|
||||
printf("diskTemp : %f\n", info.kdk_real_get_disk_temperature(argv[argc -1]));
|
||||
printf("cpuTemp: %f\n", info.kdk_real_get_cpu_temperature());
|
||||
printf("netSpeed : %f\n", info.kdk_real_get_net_speed());
|
||||
return 0;
|
||||
}
|
|
@ -8,7 +8,7 @@ find_package(PkgConfig)
|
|||
add_library(kysysinfo SHARED ${SOURCESCODE})
|
||||
set_target_properties(kysysinfo PROPERTIES VERSION 2.0.0 SOVERSION 1)
|
||||
add_executable(kysysinfo-test test/kysysinfo_test.c)
|
||||
target_link_libraries(kysysinfo dl kylog systemd kyconf X11 Xrandr libcjson.so ${GLIBC_LIB} ${DBUS_LIB} ${DBUS_GLIB_LIB})
|
||||
target_link_libraries(kysysinfo dl kylog systemd kyconf X11 Xrandr libcjson.so pci kmod ${GLIBC_LIB} ${DBUS_LIB} ${DBUS_GLIB_LIB})
|
||||
target_link_libraries(kysysinfo-test kysysinfo libcjson.so)
|
||||
# target_link_libraries(kysysinfo-test kysysinfo kylin-activation kylog systemd kyconf ${GLIBC_LIB} ${DBUS_LIB} ${DBUS_GLIB_LIB})
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -31,6 +31,19 @@ typedef struct {
|
|||
char *update_version; //补丁版本
|
||||
} version_t;
|
||||
|
||||
struct KPci
|
||||
{
|
||||
char slot_path[16];
|
||||
char class_name[128];
|
||||
char product_name[128];
|
||||
unsigned char rev;
|
||||
char ss_name[256];
|
||||
char driver_use[1024];
|
||||
char **modules;
|
||||
int module_count;
|
||||
struct KPci *next;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取操作系统架构信息
|
||||
*
|
||||
|
@ -154,13 +167,84 @@ extern version_t kdk_system_get_version_detaile();
|
|||
extern char** kdk_system_get_resolving_power();
|
||||
|
||||
/**
|
||||
* @brief 获取显示系统版本类别
|
||||
* @brief 获取显示系统硬件版本类别
|
||||
*
|
||||
* @return char* 成功返回字符串系统版本类别,失败返回NULL。返回的字符串需要被 free 释放
|
||||
* @return char* 成功返回字符串系统版本硬件类别,版本类别有{Tablet, MaxTablet},Tablet-平板,MaxTablet-大屏;
|
||||
* 失败返回NULL,未读到文件或字段返回字符串none。返回的字符串需要被 free 释放。
|
||||
*/
|
||||
|
||||
extern char* kdk_system_get_systemCategory();
|
||||
|
||||
/**
|
||||
* @brief 获取云平台类型
|
||||
*
|
||||
* @return char* 成功返回字符串应用场景,应用场景有{EDU},EDU-教育;失败返回NULL,未读到文件或字段返回字符串none。
|
||||
* 返回的字符串需要被 free 释放。
|
||||
*/
|
||||
|
||||
// extern char* kdk_system_get_cloudPlatformType();
|
||||
|
||||
/**
|
||||
* @brief 获取系统开机时间
|
||||
*
|
||||
* @return char** 开机时间
|
||||
*/
|
||||
|
||||
extern char** kdk_system_get_startup_time();
|
||||
|
||||
/**
|
||||
* @brief 获取系统关机时间
|
||||
*
|
||||
* @return char** 关机时间
|
||||
*/
|
||||
|
||||
extern char** kdk_system_get_shutdown_time();
|
||||
|
||||
/**
|
||||
* @brief 获取整机制造商
|
||||
*
|
||||
* @return char* 整机制造商,失败返回NULL。返回的字符串需要被 free 释放
|
||||
*/
|
||||
|
||||
extern char *kdk_get_host_vendor();
|
||||
|
||||
/**
|
||||
* @brief 获取整机型号
|
||||
*
|
||||
* @return char* 整机型号,失败返回NULL。返回的字符串需要被 free 释放
|
||||
*/
|
||||
|
||||
extern char *kdk_get_host_product();
|
||||
|
||||
/**
|
||||
* @brief 获取整机序列号
|
||||
*
|
||||
* @return char* 整机序列号,失败返回NULL。返回的字符串需要被 free 释放
|
||||
*/
|
||||
|
||||
extern char *kdk_get_host_serial();
|
||||
|
||||
/**
|
||||
* @brief 获取主机名
|
||||
*
|
||||
* @return char* 主机名,失败返回NULL。返回的字符串需要被 free 释放
|
||||
*/
|
||||
extern char *kdk_system_get_hostName();
|
||||
|
||||
/**
|
||||
* @brief 获取操作系统位数
|
||||
*
|
||||
* @return int 返回系统位数
|
||||
*/
|
||||
extern int kdk_system_get_word();
|
||||
|
||||
/**
|
||||
* @brief 获取操作系统构建时间
|
||||
*
|
||||
* @return char* 操作系统构建时间,失败返回NULL。返回的字符串需要被 free 释放
|
||||
*/
|
||||
extern char *kdk_system_get_buildTime();
|
||||
|
||||
/**
|
||||
* @brief 用于回收字符串列表
|
||||
*
|
||||
|
@ -168,6 +252,26 @@ extern char* kdk_system_get_systemCategory();
|
|||
*/
|
||||
extern inline void kdk_resolving_freeall(char **ptr);
|
||||
|
||||
/**
|
||||
* @brief 获取总线信息
|
||||
* @return pci总线信息结构体,具体参考返回结构体,lspci -k的返回
|
||||
*/
|
||||
extern struct KPci *kdk_hw_get_pci_info();
|
||||
|
||||
/**
|
||||
* @brief 释放由kdk_hw_get_pci_info返回的pci总线信息结构体
|
||||
*
|
||||
* @param disk 由kdk_hw_get_pci_info返回的结构体指针
|
||||
*/
|
||||
extern void kdk_hw_free_pci_info(struct KPci *info);
|
||||
|
||||
/**
|
||||
* @brief 获取应用场景
|
||||
*
|
||||
* @return char* 成功返回字符串应用场景,应用场景有{EDU},失败返回NULL。返回的字符串需要被 free 释放
|
||||
*/
|
||||
extern char *kdk_system_get_appScene();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -62,8 +62,76 @@ int main()
|
|||
kdk_resolving_freeall(name);
|
||||
|
||||
char *ver = kdk_system_get_systemCategory();
|
||||
printf("系统版本类别 = %s\n", ver);
|
||||
printf("系统硬件版本类别 = %s\n", ver);
|
||||
free(ver);
|
||||
|
||||
// ver = kdk_system_get_cloudPlatformType();
|
||||
// printf("云平台类型 = %s\n", ver);
|
||||
// free(ver);
|
||||
|
||||
char **ud_time = kdk_system_get_startup_time();
|
||||
count = 0;
|
||||
while (ud_time[count])
|
||||
{
|
||||
printf("开机时间 = %s\n", ud_time[count]);
|
||||
count++;
|
||||
}
|
||||
kdk_resolving_freeall(ud_time);
|
||||
|
||||
ud_time = kdk_system_get_shutdown_time();
|
||||
count = 0;
|
||||
while (ud_time[count])
|
||||
{
|
||||
printf("关机时间 = %s\n", ud_time[count]);
|
||||
count++;
|
||||
}
|
||||
kdk_resolving_freeall(ud_time);
|
||||
|
||||
res = kdk_get_host_vendor();
|
||||
printf("整机制造商 = %s\n", res);
|
||||
free(res);
|
||||
|
||||
res = kdk_get_host_product();
|
||||
printf("整机型号 = %s\n", res);
|
||||
free(res);
|
||||
|
||||
res = kdk_get_host_serial();
|
||||
printf("整机序列号 = %s\n", res);
|
||||
free(res);
|
||||
|
||||
res = kdk_system_get_buildTime();
|
||||
printf("构建时间:%s\n", res);
|
||||
free(res);
|
||||
|
||||
res = kdk_system_get_hostName();
|
||||
printf("主机名:%s\n", res);
|
||||
free(res);
|
||||
|
||||
printf("系统位数:%d\n", kdk_system_get_word());
|
||||
|
||||
struct KPci *pci = kdk_hw_get_pci_info();
|
||||
struct KPci *tmp = pci;
|
||||
while (tmp)
|
||||
{
|
||||
printf("slot path : %s\n", tmp->slot_path);
|
||||
printf("\tclass name :%s\n", tmp->class_name);
|
||||
printf("\tproduct name :%s\n", tmp->product_name);
|
||||
printf("\trev :%02x\n", tmp->rev);
|
||||
printf("\tsubsystem name :%s\n", tmp->ss_name);
|
||||
printf("\tdriver user :%s\n", tmp->driver_use);
|
||||
printf("\tmodules :");
|
||||
for(int i = 0; i < tmp->module_count; i++)
|
||||
{
|
||||
printf("\t%s", tmp->modules[i]);
|
||||
}
|
||||
printf("\n");
|
||||
tmp = tmp->next;
|
||||
}
|
||||
kdk_hw_free_pci_info(pci);
|
||||
|
||||
res = kdk_system_get_appScene();
|
||||
printf("应用场景:%s\n", res);
|
||||
free(res);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -15,8 +15,11 @@
|
|||
#include <libintl.h>
|
||||
#include <locale.h>
|
||||
|
||||
char path[50]; //用户修改后配置文件路径
|
||||
#define PATH_MAX 50
|
||||
char path[100]; //用户修改后配置文件路径
|
||||
#define PATH_MAX 100
|
||||
|
||||
#define LOCALEDIR "/usr/share/locale/"
|
||||
#define GETTEXT_PACKAGE "kysdk-date"
|
||||
|
||||
pthread_mutex_t lock;
|
||||
u_int8_t g_Flag; // 控制启用常驻定时器还是临时定时器
|
||||
|
@ -45,78 +48,124 @@ static void *printDate(DBusConnection *ptr)
|
|||
time_t current;
|
||||
time(¤t);
|
||||
now = localtime(¤t);
|
||||
char *value = malloc(sizeof(char) * 64);
|
||||
char *tvalue = malloc(sizeof(char) * 64);
|
||||
char *tmpvalue = malloc(sizeof(char) * 64);
|
||||
char value[64] = "\0";
|
||||
char tvalue[64] = "\0";
|
||||
char tmpvalue[64] = "\0";
|
||||
char tmp[40] = {0};
|
||||
GKeyFile *config = g_key_file_new();
|
||||
char *lang = getenv("LANG");
|
||||
char canonical_filename[PATH_MAX] = "\0";
|
||||
|
||||
if (!realpath(path, canonical_filename) || !verify_file(canonical_filename))
|
||||
goto out;
|
||||
|
||||
g_key_file_load_from_file(config, canonical_filename, 0, NULL);
|
||||
|
||||
value = g_key_file_get_string(config, "DATEFORMAT", "DATE_FORMAT", NULL);
|
||||
if(value == NULL)
|
||||
char *env_time = getenv("LC_TIME");
|
||||
if(!env_time)
|
||||
{
|
||||
strcpy(tmpvalue, "**/**/**");
|
||||
strftime(tmp, sizeof(tmp), "%Y/%m/%d", localtime(¤t));
|
||||
}else{
|
||||
strcpy(tmpvalue, value);
|
||||
if(strstr(value, "*-*-*"))
|
||||
env_time = " ";
|
||||
}
|
||||
|
||||
// if (!realpath(path, canonical_filename) || !verify_file(canonical_filename))
|
||||
// goto out;
|
||||
|
||||
g_key_file_load_from_file(config, path, 0, NULL);
|
||||
|
||||
char *gkey = g_key_file_get_string(config, "DATEFORMAT", "DATE_FORMAT", NULL);
|
||||
if(gkey == NULL)
|
||||
{
|
||||
strcpy(value, "**/**/**");
|
||||
}
|
||||
else{
|
||||
strcpy(value, gkey);
|
||||
}
|
||||
|
||||
strcpy(tmpvalue, value);
|
||||
if(strstr(value, "*-*-*"))
|
||||
{
|
||||
if(strstr(env_time, "en_US"))
|
||||
{
|
||||
sprintf(tmp, "%d-%d-%d", now->tm_mon+1, now->tm_mday, (now->tm_year)%100);
|
||||
}else{
|
||||
sprintf(tmp, "%d-%d-%d", (now->tm_year)%100, now->tm_mon+1, now->tm_mday);
|
||||
}
|
||||
if(strstr(value, "*/*/*"))
|
||||
}
|
||||
if(strstr(value, "*/*/*"))
|
||||
{
|
||||
if(strstr(env_time, "en_US"))
|
||||
{
|
||||
sprintf(tmp, "%d/%d/%d", now->tm_mon+1, now->tm_mday, (now->tm_year)%100);
|
||||
}else{
|
||||
sprintf(tmp, "%d/%d/%d", (now->tm_year)%100, now->tm_mon+1, now->tm_mday);
|
||||
}
|
||||
if(strstr(value, "*.*.*"))
|
||||
}
|
||||
if(strstr(value, "*.*.*"))
|
||||
{
|
||||
if(strstr(env_time, "en_US"))
|
||||
{
|
||||
sprintf(tmp, "%d.%d.%d", now->tm_mon+1, now->tm_mday, (now->tm_year)%100);
|
||||
}else{
|
||||
sprintf(tmp, "%d.%d.%d", (now->tm_year)%100, now->tm_mon+1, now->tm_mday);
|
||||
}
|
||||
if(strstr(value, "*年*月*日"))
|
||||
}
|
||||
if(strstr(value, "*年*月*日"))
|
||||
{
|
||||
if(strstr(lang, "en_US"))
|
||||
{
|
||||
if(strstr(lang, "en_US"))
|
||||
{
|
||||
char tdate[20];
|
||||
strftime(tdate, sizeof(tdate), "%b", localtime(¤t));
|
||||
sprintf(tmp, "%s %d,%d", tdate, now->tm_mday, (1900 + now->tm_year)%100 );
|
||||
strcpy(tmpvalue, "*year*mon*day");
|
||||
}else{
|
||||
sprintf(tmp, gettext("%d_year%d_mon%d_day"), (now->tm_year)%100, now->tm_mon+1, now->tm_mday);
|
||||
strcpy(tmpvalue, gettext("*year*mon*day"));
|
||||
}
|
||||
}
|
||||
|
||||
if(strstr(value, "**-**-**"))
|
||||
{
|
||||
strftime(tmp, sizeof(tmp), "%Y-%m-%d", localtime(¤t));
|
||||
}
|
||||
if(strstr(value, "**/**/**"))
|
||||
{
|
||||
strftime(tmp, sizeof(tmp), "%Y/%m/%d", localtime(¤t));
|
||||
}
|
||||
if(strstr(value, "**.**.**"))
|
||||
{
|
||||
strftime(tmp, sizeof(tmp), "%Y.%m.%d", localtime(¤t));
|
||||
}
|
||||
if(strstr(value, "**年**月**日"))
|
||||
{
|
||||
if(strstr(lang, "en_US"))
|
||||
{
|
||||
strftime(tmp, sizeof(tmp), "%b %d,%Y", localtime(¤t));
|
||||
strcpy(tmpvalue, "**year**mon**day");
|
||||
}else{
|
||||
strftime(tmp, sizeof(tmp), gettext("%Y_year%m_mon%d_day"), localtime(¤t));
|
||||
strcpy(tmpvalue, gettext("**year**mon**day"));
|
||||
}
|
||||
char tdate[20];
|
||||
strftime(tdate, sizeof(tdate), "%b", localtime(¤t));
|
||||
sprintf(tmp, "%s %d,%d", tdate, now->tm_mday, (1900 + now->tm_year)%100 );
|
||||
strcpy(tmpvalue, "*year*mon*day");
|
||||
}else{
|
||||
sprintf(tmp, gettext("%d_year%d_mon%d_day"), (now->tm_year)%100, now->tm_mon+1, now->tm_mday);
|
||||
strcpy(tmpvalue, gettext("*year*mon*day"));
|
||||
}
|
||||
}
|
||||
value = g_key_file_get_string(config, "DATEFORMAT", "TIME_FORMAT", NULL);
|
||||
if(value == NULL)
|
||||
|
||||
if(strstr(value, "**-**-**"))
|
||||
{
|
||||
if(strstr(env_time, "en_US"))
|
||||
{
|
||||
strftime(tmp, sizeof(tmp), "%m-%d-%Y", localtime(¤t));
|
||||
}else{
|
||||
strftime(tmp, sizeof(tmp), "%Y-%m-%d", localtime(¤t));
|
||||
}
|
||||
}
|
||||
if(strstr(value, "**/**/**"))
|
||||
{
|
||||
if(strstr(env_time, "en_US"))
|
||||
{
|
||||
strftime(tmp, sizeof(tmp), "%m/%d/%Y", localtime(¤t));
|
||||
}else{
|
||||
strftime(tmp, sizeof(tmp), "%Y/%m/%d", localtime(¤t));
|
||||
}
|
||||
}
|
||||
if(strstr(value, "**.**.**"))
|
||||
{
|
||||
if(strstr(env_time, "en_US"))
|
||||
{
|
||||
strftime(tmp, sizeof(tmp), "%m.%d.%Y", localtime(¤t));
|
||||
}else{
|
||||
strftime(tmp, sizeof(tmp), "%Y.%m.%d", localtime(¤t));
|
||||
}
|
||||
}
|
||||
if(strstr(value, "**年**月**日"))
|
||||
{
|
||||
if(strstr(lang, "en_US"))
|
||||
{
|
||||
strftime(tmp, sizeof(tmp), "%b %d,%Y", localtime(¤t));
|
||||
strcpy(tmpvalue, "**year**mon**day");
|
||||
}else{
|
||||
strftime(tmp, sizeof(tmp), gettext("%Y_year%m_mon%d_day"), localtime(¤t));
|
||||
strcpy(tmpvalue, gettext("**year**mon**day"));
|
||||
}
|
||||
}
|
||||
|
||||
char *gvalue = g_key_file_get_string(config, "DATEFORMAT", "TIME_FORMAT", NULL);
|
||||
if(gvalue == NULL)
|
||||
{
|
||||
strcpy(value, "24");
|
||||
}
|
||||
else{
|
||||
strcpy(value, gvalue);
|
||||
}
|
||||
|
||||
if(strstr(value, "24"))
|
||||
{
|
||||
if(strstr(lang, "en_US"))
|
||||
{
|
||||
|
@ -125,23 +174,12 @@ static void *printDate(DBusConnection *ptr)
|
|||
strcpy(tvalue, gettext("24-hour clock"));
|
||||
}
|
||||
}else{
|
||||
if(strstr(value, "24"))
|
||||
if(strstr(lang, "en_US"))
|
||||
{
|
||||
if(strstr(lang, "en_US"))
|
||||
{
|
||||
strcpy(tvalue, "24-hour clock");
|
||||
}else{
|
||||
strcpy(tvalue, gettext("24-hour clock"));
|
||||
}
|
||||
strcpy(tvalue, "12-hour clock");
|
||||
}else{
|
||||
if(strstr(lang, "en_US"))
|
||||
{
|
||||
strcpy(tvalue, "12-hour clock");
|
||||
}else{
|
||||
strcpy(tvalue, gettext("12-hour clock"));
|
||||
}
|
||||
strcpy(tvalue, gettext("12-hour clock"));
|
||||
}
|
||||
// strcpy(tvalue, value);
|
||||
}
|
||||
|
||||
if (g_DateChanged == 1)
|
||||
|
@ -166,12 +204,258 @@ static void *printDate(DBusConnection *ptr)
|
|||
g_key_file_free(config);
|
||||
}
|
||||
out:
|
||||
free(value);
|
||||
free(tvalue);
|
||||
free(tmpvalue);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *print_longDate(DBusConnection *ptr)
|
||||
{
|
||||
setlocale (LC_ALL, "");
|
||||
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
|
||||
textdomain (GETTEXT_PACKAGE);
|
||||
|
||||
DBusConnection *conn = ptr;
|
||||
DBusMessage *msg;
|
||||
DBusMessageIter args;
|
||||
dbus_uint32_t serial = 0;
|
||||
struct tm *now;
|
||||
time_t current;
|
||||
time(¤t);
|
||||
now = localtime(¤t);
|
||||
char value[64] = "\0";
|
||||
char *tvalue = (char *)malloc(sizeof(char) * 64);
|
||||
char *tmpvalue = (char *)malloc(sizeof(char) * 64);
|
||||
if(!tvalue || !tmpvalue)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
char tmp[64] = "\0";
|
||||
GKeyFile *config = g_key_file_new();
|
||||
char *lang = getenv("LANG");
|
||||
char canonical_filename[PATH_MAX] = "\0";
|
||||
|
||||
g_key_file_load_from_file(config, path, 0, NULL);
|
||||
|
||||
char *gkey = g_key_file_get_string(config, "DATEFORMAT", "LONG_DATE_FORMAT", NULL);
|
||||
if(gkey == NULL)
|
||||
{
|
||||
strcpy(value, "yyyy MM dd");
|
||||
}
|
||||
else{
|
||||
strcpy(value, gkey);
|
||||
}
|
||||
|
||||
strcpy(tmpvalue, value);
|
||||
|
||||
if(strstr(value, "yy M d"))
|
||||
{
|
||||
if(strstr(lang, "en_US"))
|
||||
{
|
||||
char tdate[20];
|
||||
strftime(tdate, sizeof(tdate), "%b", localtime(¤t));
|
||||
sprintf(tmp, "%s %d,%d", tdate, now->tm_mday, (1900 + now->tm_year)%100 );
|
||||
}else{
|
||||
sprintf(tmp, gettext("%d_year%d_mon%d_day"), (now->tm_year)%100, now->tm_mon+1, now->tm_mday);
|
||||
}
|
||||
}
|
||||
|
||||
if(strstr(value, "yyyy MM dd"))
|
||||
{
|
||||
if(strstr(lang, "en_US"))
|
||||
{
|
||||
strftime(tmp, sizeof(tmp), "%b %d,%Y", localtime(¤t));
|
||||
}else{
|
||||
strftime(tmp, sizeof(tmp), gettext("%Y_year%m_mon%d_day"), localtime(¤t));
|
||||
}
|
||||
}
|
||||
strcpy(tvalue, tmp);
|
||||
|
||||
if (g_DateChanged == 1)
|
||||
{
|
||||
msg = dbus_message_new_signal("/com/kylin/kysdk/Date",
|
||||
"com.kylin.kysdk.DateInterface",
|
||||
"LongDateSignal");
|
||||
if (NULL == msg)
|
||||
{
|
||||
fprintf(stderr, "Message Null\n");
|
||||
}
|
||||
// append arguments onto signal
|
||||
dbus_message_iter_init_append(msg, &args);
|
||||
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &tmpvalue);
|
||||
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &tvalue);
|
||||
dbus_connection_send(conn, msg, &serial);
|
||||
dbus_connection_flush(conn);
|
||||
dbus_message_unref(msg);
|
||||
g_key_file_free(config);
|
||||
}
|
||||
out:
|
||||
if(tmpvalue)
|
||||
free(tmpvalue);
|
||||
if(tvalue)
|
||||
free(tvalue);
|
||||
return ;
|
||||
}
|
||||
|
||||
static void *print_shortDate(DBusConnection *ptr)
|
||||
{
|
||||
setlocale (LC_ALL, "");
|
||||
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
|
||||
textdomain (GETTEXT_PACKAGE);
|
||||
|
||||
DBusConnection *conn = ptr;
|
||||
DBusMessage *msg;
|
||||
DBusMessageIter args;
|
||||
dbus_uint32_t serial = 0;
|
||||
struct tm *now;
|
||||
time_t current;
|
||||
time(¤t);
|
||||
now = localtime(¤t);
|
||||
char value[64] = "\0";
|
||||
char tvalue[64] = "\0";
|
||||
char *tmpvalue = (char *)malloc(sizeof(char) * 64);
|
||||
char tmp[64] = "\0";
|
||||
char *str_tmp = (char *)malloc(sizeof(char) * 64);
|
||||
if(!tmpvalue || !str_tmp)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
GKeyFile *config = g_key_file_new();
|
||||
char canonical_filename[PATH_MAX] = "\0";
|
||||
char *lang = getenv("LANG");
|
||||
char *env_time = getenv("LC_TIME");
|
||||
if(!env_time)
|
||||
{
|
||||
env_time = " ";
|
||||
}
|
||||
|
||||
// if (!realpath(path, canonical_filename) || !verify_file(canonical_filename))
|
||||
// goto out;
|
||||
|
||||
g_key_file_load_from_file(config, path, 0, NULL);
|
||||
|
||||
char *gkey = g_key_file_get_string(config, "DATEFORMAT", "SHORT_DATE_FORMAT", NULL);
|
||||
if(gkey == NULL)
|
||||
{
|
||||
if(strstr(env_time, "en_US"))
|
||||
{
|
||||
strcpy(value, "MM/dd/yyyy");
|
||||
}
|
||||
else{
|
||||
strcpy(value, "yyyy/MM/dd");
|
||||
}
|
||||
}
|
||||
else{
|
||||
strcpy(value, gkey);
|
||||
}
|
||||
|
||||
strcpy(tmpvalue, value);
|
||||
if(strstr(value, "yy-M-d"))
|
||||
{
|
||||
sprintf(tmp, "%d-%d-%d", (now->tm_year)%100, now->tm_mon+1, now->tm_mday);
|
||||
}
|
||||
else if(strstr(value, "M-d-yy"))
|
||||
{
|
||||
sprintf(tmp, "%d-%d-%d", now->tm_mon+1, now->tm_mday, (now->tm_year)%100);
|
||||
}
|
||||
|
||||
else if(strstr(value, "yy/M/d"))
|
||||
{
|
||||
sprintf(tmp, "%d/%d/%d", (now->tm_year)%100, now->tm_mon+1, now->tm_mday);
|
||||
}
|
||||
else if(strstr(value, "M/d/yy"))
|
||||
{
|
||||
sprintf(tmp, "%d/%d/%d", now->tm_mon+1, now->tm_mday, (now->tm_year)%100);
|
||||
}
|
||||
|
||||
if(strstr(value, "yy.M.d"))
|
||||
{
|
||||
sprintf(tmp, "%d.%d.%d", (now->tm_year)%100, now->tm_mon+1, now->tm_mday);
|
||||
}
|
||||
else if(strstr(value, "M.d.yy"))
|
||||
{
|
||||
sprintf(tmp, "%d.%d.%d", now->tm_mon+1, now->tm_mday, (now->tm_year)%100);
|
||||
}
|
||||
|
||||
if(strstr(value, "yyyy-MM-dd"))
|
||||
{
|
||||
strftime(tmp, sizeof(tmp), "%Y-%m-%d", localtime(¤t));
|
||||
}
|
||||
else if(strstr(value, "MM-dd-yyyy"))
|
||||
{
|
||||
strftime(tmp, sizeof(tmp), "%m-%d-%Y", localtime(¤t));
|
||||
}
|
||||
|
||||
if(strstr(value, "yyyy/MM/dd"))
|
||||
{
|
||||
strftime(tmp, sizeof(tmp), "%Y/%m/%d", localtime(¤t));
|
||||
}
|
||||
else if(strstr(value, "MM/dd/yyyy"))
|
||||
{
|
||||
strftime(tmp, sizeof(tmp), "%m/%d/%Y", localtime(¤t));
|
||||
}
|
||||
|
||||
if(strstr(value, "yyyy.MM.dd"))
|
||||
{
|
||||
strftime(tmp, sizeof(tmp), "%Y.%m.%d", localtime(¤t));
|
||||
}
|
||||
else if(strstr(value, "MM.dd.yyyy"))
|
||||
{
|
||||
strftime(tmp, sizeof(tmp), "%m.%d.%Y", localtime(¤t));
|
||||
}
|
||||
|
||||
strcpy(str_tmp, tmp);
|
||||
|
||||
char *gvalue = g_key_file_get_string(config, "DATEFORMAT", "TIME_FORMAT", NULL);
|
||||
if(gvalue == NULL)
|
||||
{
|
||||
strcpy(value, "24");
|
||||
}
|
||||
else{
|
||||
strcpy(value, gvalue);
|
||||
}
|
||||
|
||||
if(strstr(value, "24"))
|
||||
{
|
||||
if(strstr(lang, "en_US"))
|
||||
{
|
||||
strcpy(tvalue, "24-hour clock");
|
||||
}else{
|
||||
strcpy(tvalue, gettext("24-hour clock"));
|
||||
}
|
||||
}else{
|
||||
if(strstr(lang, "en_US"))
|
||||
{
|
||||
strcpy(tvalue, "12-hour clock");
|
||||
}else{
|
||||
strcpy(tvalue, gettext("12-hour clock"));
|
||||
}
|
||||
}
|
||||
|
||||
if (g_DateChanged == 1)
|
||||
{
|
||||
msg = dbus_message_new_signal("/com/kylin/kysdk/Date",
|
||||
"com.kylin.kysdk.DateInterface",
|
||||
"ShortDateSignal");
|
||||
if (NULL == msg)
|
||||
{
|
||||
fprintf(stderr, "Message Null\n");
|
||||
}
|
||||
// append arguments onto signal
|
||||
dbus_message_iter_init_append(msg, &args);
|
||||
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &tmpvalue);
|
||||
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &str_tmp);
|
||||
dbus_connection_send(conn, msg, &serial);
|
||||
dbus_connection_flush(conn);
|
||||
dbus_message_unref(msg);
|
||||
g_key_file_free(config);
|
||||
}
|
||||
out:
|
||||
if(tmpvalue)
|
||||
free(tmpvalue);
|
||||
if(str_tmp)
|
||||
free(str_tmp);
|
||||
return ;
|
||||
}
|
||||
|
||||
void *actionDateChanged(void *ptr)
|
||||
{
|
||||
DBusConnection *conn = NULL;
|
||||
|
@ -180,18 +464,11 @@ void *actionDateChanged(void *ptr)
|
|||
int fd = inotify_init();
|
||||
|
||||
char *homeDir = NULL;
|
||||
char canonical_filename[PATH_MAX] = "\0";
|
||||
|
||||
homeDir = getenv("HOME");
|
||||
sprintf(path, "%s/.config/date.conf", homeDir);
|
||||
sprintf(path, "%s/.config/kydate/dateformat.conf", homeDir);
|
||||
|
||||
if (!realpath(path, canonical_filename) || !verify_file(canonical_filename))
|
||||
{
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int fdate = inotify_add_watch(fd, canonical_filename, IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF );
|
||||
int fdate = inotify_add_watch(fd, path, IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF );
|
||||
if (fdate < 0)
|
||||
{
|
||||
close(fd);
|
||||
|
@ -203,6 +480,8 @@ void *actionDateChanged(void *ptr)
|
|||
{
|
||||
g_DateChanged = 1;
|
||||
printDate(conn);
|
||||
print_longDate(conn);
|
||||
print_shortDate(conn);
|
||||
}
|
||||
}
|
||||
inotify_rm_watch(fd, fdate);
|
||||
|
@ -214,15 +493,9 @@ int monitorSystemDateChange(int fd){
|
|||
|
||||
char *homeDir = NULL;
|
||||
char *realpath_res = NULL;
|
||||
char canonical_filename[PATH_MAX] = "\0";
|
||||
|
||||
homeDir = getenv("HOME");
|
||||
sprintf(path, "%s/.config/date.conf", homeDir);
|
||||
|
||||
if (!realpath(path, canonical_filename) || !verify_file(canonical_filename))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
sprintf(path, "%s/.config/kydate/dateformat.conf", homeDir);
|
||||
|
||||
char buf[BUFSIZ];
|
||||
buf[sizeof(buf) - 1] = 0;
|
||||
|
@ -239,7 +512,7 @@ int monitorSystemDateChange(int fd){
|
|||
fprintf(stdout, "%s --- %s\n", event->name, "IN_DELETE | IN_MODIFY");
|
||||
if (event->mask & (IN_DELETE | IN_DELETE_SELF))
|
||||
{
|
||||
int fdate = inotify_add_watch(fd, canonical_filename, IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF );
|
||||
int fdate = inotify_add_watch(fd, path, IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF );
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -275,6 +548,12 @@ const char *server_introspection_xml =
|
|||
" <signal name='DateSignal'>\n"
|
||||
" <arg name='date' type='s' />\n"
|
||||
" </signal>"
|
||||
" <signal name='LongDateSignal'>\n"
|
||||
" <arg name='date' type='s' />\n"
|
||||
" </signal>"
|
||||
" <signal name='ShortDateSignal'>\n"
|
||||
" <arg name='date' type='s' />\n"
|
||||
" </signal>"
|
||||
" </interface>\n"
|
||||
|
||||
"</node>\n";
|
||||
|
|
|
@ -6,3 +6,4 @@ Name=SDK-DATE
|
|||
Icon=
|
||||
Keywords=session;kysdk-systime-date
|
||||
Comment=This session date you into sdk
|
||||
NoDisplay=true
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -19,14 +19,6 @@ typedef struct _kdk_logn_dateinfo{
|
|||
char *week;
|
||||
}kdk_logn_dateinfo;
|
||||
|
||||
|
||||
#define CONF_FILE_PATH "/etc/kydate/dateform.conf"
|
||||
#define LOCALEDIR "/usr/share/locale/"
|
||||
#define GETTEXT_PACKAGE "kysdk-date"
|
||||
#define MAXSIZE 80
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief 获取系统支持的日期格式
|
||||
*
|
||||
|
@ -150,6 +142,76 @@ extern void kdk_free_dateinfo(kdk_dateinfo *date);
|
|||
*/
|
||||
extern void kdk_free_logn_dateinfo(kdk_logn_dateinfo *date);
|
||||
|
||||
/**
|
||||
* @brief 设置日期长格式
|
||||
*
|
||||
* @param format 长格式的一种
|
||||
* @return int 设置成功返回0;其它值,失败。
|
||||
*/
|
||||
extern int kdk_system_set_long_dateformat(char *format);
|
||||
|
||||
/**
|
||||
* @brief 设置日期短格式
|
||||
*
|
||||
* @param format 短格式中的一种
|
||||
* @return int 设置成功返回0;其它值,失败。
|
||||
*/
|
||||
extern int kdk_system_set_short_dateformat(char *format);
|
||||
|
||||
/**
|
||||
* @brief 获取当前的长格式日期
|
||||
*
|
||||
* @return char* 用户的当前长格式的日期
|
||||
*/
|
||||
extern char* kdk_system_get_longformat_date();
|
||||
|
||||
/**
|
||||
* @brief 获取当前的短格式日期
|
||||
*
|
||||
* @return char* 用户的当前短格式的日期
|
||||
*/
|
||||
extern char* kdk_system_get_shortformat_date();
|
||||
|
||||
/**
|
||||
* @brief 获取长格式
|
||||
*
|
||||
* @return char*,用户设置的长格式,长格式有{yyyy MM dd,yy M d},默认yyyy MM dd 格式。
|
||||
*/
|
||||
extern char* kdk_system_get_longformat();
|
||||
|
||||
/**
|
||||
* @brief 获取短格式
|
||||
*
|
||||
* @return char*,用户设置的短格式,短格式有{yyyy/MM/dd,yy/M/d,
|
||||
* yyyy-MM-dd,yy-M-d,yyyy.MM.dd,yy.M.d},默认 yyyy/MM/dd 格式。
|
||||
*/
|
||||
extern char* kdk_system_get_shortformat();
|
||||
|
||||
/**
|
||||
* @brief 长格式转化
|
||||
*
|
||||
* @param struct tm *,需要转化的时间。
|
||||
* @return char*,用户设置的长格式形式输出转化的日期。
|
||||
*/
|
||||
extern char* kdk_system_longformat_transform(struct tm *ptr);
|
||||
|
||||
/**
|
||||
* @brief 短格式转化
|
||||
*
|
||||
* @param struct tm *,需要转化的时间。
|
||||
* @return char*,用户设置的短格式形式输出转化的日期。如 2023/06/09。
|
||||
*/
|
||||
extern char* kdk_system_shortformat_transform(struct tm *ptr);
|
||||
|
||||
/**
|
||||
* @brief 获取登录锁屏的时间,星期,长格式日期
|
||||
*
|
||||
* @param user 用户名
|
||||
* @return kdk_logn_dateinfo,成员:date(char*);描述:登录配置文件中的长格式的日期;
|
||||
* 成员:time(char*);描述:登录配置文件中的格式的时间;成员:week(char*);描述:当前星期。
|
||||
*/
|
||||
extern kdk_logn_dateinfo *kdk_system_login_lock_dateinfo(char *user);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -157,4 +219,4 @@ extern void kdk_free_logn_dateinfo(kdk_logn_dateinfo *date);
|
|||
#endif
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
*/
|
||||
|
|
|
@ -55,7 +55,6 @@ static void *printClock(void *ptr)
|
|||
{
|
||||
char *buf = calloc(1, 128);
|
||||
sprintf(buf, "%04d/%02d/%02d %02d:%02d:%02d", now->tm_year + 1900, now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);
|
||||
printf("%s\n", buf);
|
||||
|
||||
msg = dbus_message_new_signal("/com/kylin/kysdk/Timer",
|
||||
"com.kylin.kysdk.TimeInterface",
|
||||
|
@ -135,7 +134,7 @@ void *startBroadcastSystemTimePerMin(void *tmp)
|
|||
{
|
||||
// 若临时定时器已启动,则不做处理
|
||||
// 时钟发生变化,需要进行对时调整;关闭常驻定时器timerID,启动临时定时器
|
||||
printf("Get Time Changed signal or mis-synced. stop timerID %zd\n", periodicTimerID);
|
||||
// printf("Get Time Changed signal or mis-synced. stop timerID %zd\n", periodicTimerID);
|
||||
kdk_timer_stop(periodicTimerID);
|
||||
g_TimeChanged = 0;
|
||||
g_TimeSync = 0;
|
||||
|
@ -148,7 +147,7 @@ void *startBroadcastSystemTimePerMin(void *tmp)
|
|||
{
|
||||
// 当启动常驻定时器时,临时定时器肯定不需要再存在了
|
||||
periodicTimerID = kdk_timer_start(1000 * 60, printClock, KTIMER_PERIODIC, KTIMER_RELATIVE, conn, 0);
|
||||
printf("start periodic timer with ID %zd\n", periodicTimerID);
|
||||
// printf("start periodic timer with ID %zd\n", periodicTimerID);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,7 +187,7 @@ void *actionTimeChanged(void *ptr)
|
|||
{
|
||||
if (monitorSystemTimeChange() == 1)
|
||||
{
|
||||
printf("System Time Changed.\n");
|
||||
// printf("System Time Changed.\n");
|
||||
g_Flag = 1;
|
||||
if (g_Flag)
|
||||
{
|
||||
|
@ -240,7 +239,7 @@ void *actionTimeZoneChanged(void *ptr)
|
|||
{
|
||||
if (monitorSystemTimeZoneChange() == 1)
|
||||
{
|
||||
printf("System Time Changed.\n");
|
||||
// printf("System Time Changed.\n");
|
||||
g_Flag = 1;
|
||||
if (g_Flag)
|
||||
{
|
||||
|
@ -540,7 +539,7 @@ int main(void)
|
|||
pthread_attr_init(&tt);
|
||||
pthread_attr_setdetachstate(&tt, PTHREAD_CREATE_DETACHED);
|
||||
pthread_create(&dd, &tt, startBroadcastSystemTimePerMin, conn);
|
||||
printf("Starting dbus tiny server v%s\n", version);
|
||||
// printf("Starting dbus tiny server v%s\n", version);
|
||||
mainloop = g_main_loop_new(NULL, false);
|
||||
/* Set up the DBus connection to work in a GLib event loop */
|
||||
dbus_connection_setup_with_g_main(conn, NULL);
|
||||
|
|
|
@ -9,76 +9,115 @@
|
|||
|
||||
int main()
|
||||
{
|
||||
char **res = kdk_system_get_dateformat();
|
||||
size_t index = 0;
|
||||
while (res[index])
|
||||
{
|
||||
printf("系统支持格式返回日期:%s\n",res[index]);
|
||||
index ++;
|
||||
}
|
||||
kdk_date_freeall(res);
|
||||
// char **res = kdk_system_get_dateformat();
|
||||
// size_t index = 0;
|
||||
// while (res[index])
|
||||
// {
|
||||
// printf("系统支持格式返回日期:%s\n",res[index]);
|
||||
// index ++;
|
||||
// }
|
||||
// kdk_date_freeall(res);
|
||||
|
||||
int ret = kdk_system_set_dateformat("22/2/1");
|
||||
printf("ret = %d\n",ret);
|
||||
|
||||
// ret = kdk_system_set_24_timeformat();
|
||||
// int ret = kdk_system_set_dateformat("22-1-2");
|
||||
// printf("ret = %d\n",ret);
|
||||
int date = kdk_system_set_12_timeformat();
|
||||
|
||||
char *dt = kdk_system_get_now_dateformat();
|
||||
printf("tt = %s\n", dt);
|
||||
free(dt);
|
||||
char *tt = kdk_system_get_now_timeformat();
|
||||
printf("tt = %s\n", tt);
|
||||
free(tt);
|
||||
// int date = kdk_system_set_12_timeformat();
|
||||
|
||||
struct tm ptr;
|
||||
time_t str;
|
||||
char buf[80];
|
||||
// // ret = kdk_system_set_24_timeformat();
|
||||
// // // printf("ret = %d\n",ret);
|
||||
|
||||
// char *dt = kdk_system_get_now_dateformat();
|
||||
// printf("tt = %s\n", dt);
|
||||
// free(dt);
|
||||
// char *tt = kdk_system_get_now_timeformat();
|
||||
// printf("tt = %s\n", tt);
|
||||
// free(tt);
|
||||
|
||||
// struct tm ptr;
|
||||
|
||||
// ptr.tm_year = 2322;
|
||||
// ptr.tm_mon = 9;
|
||||
// ptr.tm_mday = 3;
|
||||
// ptr.tm_hour = 23;
|
||||
// ptr.tm_min = 50;
|
||||
// ptr.tm_sec = 21;
|
||||
// ptr.tm_isdst = 0;
|
||||
// printf("%d\n", ptr.tm_year);
|
||||
// printf("test\n");
|
||||
// kdk_dateinfo *test = kdk_system_tran_dateformat(&ptr);
|
||||
// printf("%s ;%s ; %s\n",test->date, test->time, test->timesec);
|
||||
// kdk_free_dateinfo(test);
|
||||
|
||||
// char* value = kdk_system_nowtime();
|
||||
// printf("value = %s\n", value);
|
||||
// free(value);
|
||||
|
||||
// char* tvalue = kdk_system_nowdate();
|
||||
// printf("value = %s\n", tvalue);
|
||||
// free(tvalue);
|
||||
|
||||
// char* sw = kdk_system_shortweek();
|
||||
// printf("sw = %s\n",sw);
|
||||
// free(sw);
|
||||
|
||||
// char* lw = kdk_system_longweek();
|
||||
// printf("lw = %s\n",lw);
|
||||
// free(lw);
|
||||
|
||||
// char *se = kdk_system_second();
|
||||
// printf("se = %s\n",se);
|
||||
// free(se);
|
||||
|
||||
// kdk_logn_dateinfo *logn = kdk_system_logn_dateinfo("szm");
|
||||
// printf("date = %s,time = %s,week = %s\n",logn->date,logn->time,logn->week);
|
||||
// kdk_free_logn_dateinfo(logn);
|
||||
|
||||
// char* timt = kdk_system_gjx_time("08/01/2022");
|
||||
// printf("timt = %s\n", timt);
|
||||
// free(timt);
|
||||
|
||||
int ret = kdk_system_set_long_dateformat("2230年3月4日");
|
||||
ret = kdk_system_set_short_dateformat("22/5/3");
|
||||
|
||||
char *ld = kdk_system_get_longformat_date();
|
||||
printf("long res = %s\n", ld);
|
||||
free(ld);
|
||||
|
||||
char *sd = kdk_system_get_shortformat_date();
|
||||
printf("short res = %s\n", sd);
|
||||
free(sd);
|
||||
|
||||
char *ll = kdk_system_get_longformat();
|
||||
printf("longformat = %s\n", ll);
|
||||
free(ll);
|
||||
|
||||
char *ss = kdk_system_get_shortformat();
|
||||
printf("shortformat = %s\n", ss);
|
||||
free(ss);
|
||||
|
||||
struct tm ptr;
|
||||
|
||||
ptr.tm_year = 2322;
|
||||
ptr.tm_mon = 10;
|
||||
ptr.tm_mon = 9;
|
||||
ptr.tm_mday = 3;
|
||||
ptr.tm_hour = 12;
|
||||
ptr.tm_min = 50;
|
||||
ptr.tm_sec = 21;
|
||||
ptr.tm_isdst = 0;
|
||||
printf("%d\n", ptr.tm_year);
|
||||
printf("test\n");
|
||||
kdk_dateinfo *test = kdk_system_tran_dateformat(&ptr);
|
||||
printf("%s ;%s ; %s\n",test->date, test->time, test->timesec);
|
||||
kdk_free_dateinfo(test);
|
||||
|
||||
char* value = kdk_system_nowtime();
|
||||
printf("res = %s\n", value);
|
||||
free(value);
|
||||
char *lt = kdk_system_longformat_transform(&ptr);
|
||||
printf("longformat_transform = %s\n", lt);
|
||||
free(lt);
|
||||
|
||||
char* tvalue = kdk_system_nowdate();
|
||||
printf("value = %s\n", tvalue);
|
||||
free(tvalue);
|
||||
ptr.tm_year = 2022;
|
||||
ptr.tm_mon = 3;
|
||||
ptr.tm_mday = 2;
|
||||
|
||||
char* sw = kdk_system_shortweek();
|
||||
printf("sw = %s\n",sw);
|
||||
free(sw);
|
||||
|
||||
char* lw = kdk_system_longweek();
|
||||
printf("lw = %s\n",lw);
|
||||
free(lw);
|
||||
char *st = kdk_system_shortformat_transform(&ptr);
|
||||
printf("shortformat_transform = %s\n", st);
|
||||
free(st);
|
||||
|
||||
kdk_logn_dateinfo *info = kdk_system_login_lock_dateinfo("szm");
|
||||
printf("date = %s,time = %s,week = %s\n",info->date,info->time,info->week);
|
||||
kdk_free_logn_dateinfo(info);
|
||||
|
||||
char *se = kdk_system_second();
|
||||
printf("se = %s\n",se);
|
||||
free(se);
|
||||
|
||||
kdk_logn_dateinfo *logn = kdk_system_logn_dateinfo("szm");
|
||||
printf("date = %s,time = %s,week = %s\n",logn->date,logn->time,logn->week);
|
||||
kdk_free_logn_dateinfo(logn);
|
||||
|
||||
char* timt = kdk_system_gjx_time("08/01/2022");
|
||||
printf("timt = %s\n", timt);
|
||||
free(timt);
|
||||
|
||||
|
||||
// kdk_free_logn_dateinfo(logn);
|
||||
|
||||
// free(tvalue);
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue