update 2.2版本

This commit is contained in:
shaozhimin 2023-06-28 15:15:42 +08:00
parent e4fd7ec3e2
commit b27c7e56d6
99 changed files with 8923 additions and 43318 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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;
}
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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 001
* @return const char*
*/
extern char* kdk_bluetooth_get_manufacturer(int num);
/**
* @brief
*
* @param num 001
* @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

View File

@ -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)
{

103
src/hardware/libkydisplay.c Normal file
View File

@ -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");
}

View File

@ -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

1721
src/hardware/libkyedid.c Normal file

File diff suppressed because it is too large Load Diff

112
src/hardware/libkyedid.h Normal file
View File

@ -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 10
*/
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

229
src/hardware/libkyfan.c Normal file
View File

@ -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);
}

27
src/hardware/libkyfan.h Normal file
View File

@ -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

673
src/hardware/libkyhw.c Normal file
View File

@ -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);
}
}

110
src/hardware/libkyhw.h Normal file
View File

@ -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

View File

@ -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)

View File

@ -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
*

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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);

View File

@ -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>

View File

@ -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]);
}
}
}

View File

@ -6,3 +6,4 @@ Name=SDK-SYSTEM-SESSION-BUS
Icon=
Keywords=session;kysdk-dbus-session
Comment=This session date you into sdk
NoDisplay=true

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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
}

View File

@ -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

View File

@ -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];
}
}

View File

@ -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

View File

@ -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");
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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_ */

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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 &regular_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();
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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-
* NULLnone free
*/
extern char* kdk_system_get_systemCategory();
/**
* @brief
*
* @return char* {EDU}EDU-NULLnone
* 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

View File

@ -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;
}

View File

@ -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(&current);
now = localtime(&current);
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(&current));
}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(&current));
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(&current));
}
if(strstr(value, "**/**/**"))
{
strftime(tmp, sizeof(tmp), "%Y/%m/%d", localtime(&current));
}
if(strstr(value, "**.**.**"))
{
strftime(tmp, sizeof(tmp), "%Y.%m.%d", localtime(&current));
}
if(strstr(value, "**年**月**日"))
{
if(strstr(lang, "en_US"))
{
strftime(tmp, sizeof(tmp), "%b %d,%Y", localtime(&current));
strcpy(tmpvalue, "**year**mon**day");
}else{
strftime(tmp, sizeof(tmp), gettext("%Y_year%m_mon%d_day"), localtime(&current));
strcpy(tmpvalue, gettext("**year**mon**day"));
}
char tdate[20];
strftime(tdate, sizeof(tdate), "%b", localtime(&current));
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(&current));
}else{
strftime(tmp, sizeof(tmp), "%Y-%m-%d", localtime(&current));
}
}
if(strstr(value, "**/**/**"))
{
if(strstr(env_time, "en_US"))
{
strftime(tmp, sizeof(tmp), "%m/%d/%Y", localtime(&current));
}else{
strftime(tmp, sizeof(tmp), "%Y/%m/%d", localtime(&current));
}
}
if(strstr(value, "**.**.**"))
{
if(strstr(env_time, "en_US"))
{
strftime(tmp, sizeof(tmp), "%m.%d.%Y", localtime(&current));
}else{
strftime(tmp, sizeof(tmp), "%Y.%m.%d", localtime(&current));
}
}
if(strstr(value, "**年**月**日"))
{
if(strstr(lang, "en_US"))
{
strftime(tmp, sizeof(tmp), "%b %d,%Y", localtime(&current));
strcpy(tmpvalue, "**year**mon**day");
}else{
strftime(tmp, sizeof(tmp), gettext("%Y_year%m_mon%d_day"), localtime(&current));
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(&current);
now = localtime(&current);
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(&current));
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(&current));
}else{
strftime(tmp, sizeof(tmp), gettext("%Y_year%m_mon%d_day"), localtime(&current));
}
}
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(&current);
now = localtime(&current);
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(&current));
}
else if(strstr(value, "MM-dd-yyyy"))
{
strftime(tmp, sizeof(tmp), "%m-%d-%Y", localtime(&current));
}
if(strstr(value, "yyyy/MM/dd"))
{
strftime(tmp, sizeof(tmp), "%Y/%m/%d", localtime(&current));
}
else if(strstr(value, "MM/dd/yyyy"))
{
strftime(tmp, sizeof(tmp), "%m/%d/%Y", localtime(&current));
}
if(strstr(value, "yyyy.MM.dd"))
{
strftime(tmp, sizeof(tmp), "%Y.%m.%d", localtime(&current));
}
else if(strstr(value, "MM.dd.yyyy"))
{
strftime(tmp, sizeof(tmp), "%m.%d.%Y", localtime(&current));
}
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";

View File

@ -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

View File

@ -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
/**
* @}
*/
*/

View File

@ -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);

View File

@ -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;