#include #include #include #include #include #include #include #include #include #include #include #include #include "../os.h" #include "../../base/logger.h" #include #include #include #ifndef NDEBUG #include #endif #ifdef USE_DISK_MODEL #define PARSE_ID_FUNC parse_disk_id #define ID_FOLDER "/dev/disk/by-id" #else #define PARSE_ID_FUNC parseUUID #define ID_FOLDER "/dev/disk/by-uuid" #endif #ifdef USE_DBUS #include #endif /** *Usually uuid are hex number separated by "-". this method read up to 8 hex *numbers skipping - characters. *@param uuid uuid as read in /dev/disk/by-uuid *@param buffer_out: unsigned char buffer[8] output buffer for result */ static void parseUUID(const char *uuid, unsigned char *buffer_out, unsigned int out_size) { unsigned int i, j; char *hexuuid; unsigned char cur_character; // remove characters not in hex set size_t len = strlen(uuid); hexuuid = (char *)malloc(sizeof(char) * len); memset(buffer_out, 0, out_size); memset(hexuuid, 0, sizeof(char) * len); for (i = 0, j = 0; i < len; i++) { if (isxdigit(uuid[i])) { hexuuid[j] = uuid[i]; j++; } else { // skip continue; } } if (j % 2 == 1) { hexuuid[j++] = '0'; } hexuuid[j] = '\0'; for (i = 0; i < j / 2; i++) { sscanf(&hexuuid[i * 2], "%2hhx", &cur_character); buffer_out[i % out_size] = buffer_out[i % out_size] ^ cur_character; } free(hexuuid); } static void parse_disk_id(const char *uuid, unsigned char *buffer_out, size_t out_size) { unsigned int i; size_t len = strlen(uuid); memset(buffer_out, 0, out_size); for (i = 0; i < len; i++) { buffer_out[i % out_size] = buffer_out[i % out_size] ^ uuid[i]; } } /** * int id; char device[MAX_PATH]; unsigned char disk_sn[8]; char label[255]; int preferred; * @param blkidfile * @param diskInfos_out * @return */ static std::string getAttribute(const std::string &source, const std::string &attrName) { std::string attr_namefull = attrName + "=\""; std::size_t startpos = source.find(attr_namefull) + attr_namefull.size(); std::size_t endpos = source.find("\"", startpos); return source.substr(startpos, endpos - startpos); } FUNCTION_RETURN parse_blkid(const std::string &blkid_file_content, std::vector &diskInfos_out) { DiskInfo diskInfo; int diskNum = 0; for (std::size_t oldpos = 0, pos = 0; (pos = blkid_file_content.find("", oldpos)) != std::string::npos; oldpos = pos + 1) { std::string cur_dev = blkid_file_content.substr(oldpos, pos); diskInfo.id = diskNum++; std::string device = cur_dev.substr(cur_dev.find_last_of(">") + 1); strncpy(diskInfo.device, device.c_str(), MAX_PATH); std::string label = getAttribute(cur_dev, "PARTLABEL"); strncpy(diskInfo.label, label.c_str(), 255); std::string disk_sn = getAttribute(cur_dev, "UUID"); parseUUID(disk_sn.c_str(), diskInfo.disk_sn, sizeof(diskInfo.disk_sn)); std::string disk_type = getAttribute(cur_dev, "TYPE"); // unlikely that somebody put the swap on a removable disk. // this is a first rough guess on what can be a preferred disk for blkid devices // just in case /etc/fstab can't be accessed or it is not up to date. diskInfo.preferred = (disk_type == "swap"); diskInfos_out.push_back(diskInfo); } return FUNCTION_RETURN::FUNC_RET_OK; } #define BLKID_LOCATIONS {"/run/blkid/blkid.tab", "/etc/blkid.tab"}; static FUNCTION_RETURN getDiskInfos_blkid(std::vector &diskInfos) { const char *strs[] = BLKID_LOCATIONS; bool can_read = false; std::stringstream buffer; for (int i = 0; i < sizeof(strs) / sizeof(const char *); i++) { const char *location = strs[i]; std::ifstream t(location); if (t.is_open()) { buffer << t.rdbuf(); can_read = true; break; } } if (!can_read) { return FUNCTION_RETURN::FUNC_RET_NOT_AVAIL; } return parse_blkid(buffer.str(), diskInfos); } #define MAX_UNITS 40 FUNCTION_RETURN getDiskInfos_dev(std::vector &diskInfos) { struct dirent *dir = NULL; struct stat sym_stat; FUNCTION_RETURN result; DIR *disk_by_uuid_dir = opendir(ID_FOLDER); if (disk_by_uuid_dir == nullptr) { LOG_DEBUG("Open " ID_FOLDER " fail: %s", std::strerror(errno)); } else { const std::string base_dir(ID_FOLDER "/"); while ((dir = readdir(disk_by_uuid_dir)) != nullptr && diskInfos.size() < MAX_UNITS) { if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0 || strncmp(dir->d_name, "usb", 3) == 0) { continue; } std::string cur_dir = base_dir + dir->d_name; if (stat(cur_dir.c_str(), &sym_stat) == 0) { DiskInfo tmpDiskInfo; tmpDiskInfo.id = sym_stat.st_ino; ssize_t len = ::readlink(cur_dir.c_str(), tmpDiskInfo.device, sizeof(tmpDiskInfo.device) - 1); if (len != -1) { tmpDiskInfo.device[len] = '\0'; PARSE_ID_FUNC(dir->d_name, tmpDiskInfo.disk_sn, sizeof(tmpDiskInfo.disk_sn)); tmpDiskInfo.sn_initialized = true; tmpDiskInfo.label_initialized = false; tmpDiskInfo.preferred = false; bool found = false; for (auto diskInfo : diskInfos) { if (tmpDiskInfo.id == diskInfo.id) { found = true; break; } } if (!found) { LOG_DEBUG("Found disk inode %d device %s, sn %s", sym_stat.st_ino, tmpDiskInfo.device, dir->d_name); diskInfos.push_back(tmpDiskInfo); } } else { LOG_DEBUG("Error %s during readlink of %s", std::strerror(errno), cur_dir.c_str()); } } else { LOG_DEBUG("Error %s during stat of %s", std::strerror(errno), cur_dir.c_str()); } } closedir(disk_by_uuid_dir); } result = diskInfos.size() > 0 ? FUNCTION_RETURN::FUNC_RET_OK : FUNCTION_RETURN::FUNC_RET_NOT_AVAIL; const std::string label_dir("/dev/disk/by-label"); DIR *disk_by_label = opendir(label_dir.c_str()); if (disk_by_label != nullptr) { while ((dir = readdir(disk_by_label)) != nullptr) { if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) { continue; } std::string cur_disk_label = label_dir + "/" + dir->d_name; if (stat(cur_disk_label.c_str(), &sym_stat) == 0) { bool found = false; for (auto diskInfo : diskInfos) { if (((int)sym_stat.st_ino) == diskInfo.id) { strncpy(diskInfo.label, dir->d_name, 255 - 1); diskInfo.label_initialized = true; break; } } } else { LOG_DEBUG("Stat %s for fail:F %s", cur_disk_label.c_str(), std::strerror(errno)); } } closedir(disk_by_label); } else { LOG_DEBUG("Open %s for reading disk labels fail: %s", label_dir.c_str(), std::strerror(errno)); } return result; } /** * Try to determine removable devices: as a first guess removable devices doesn't have * an entry in /etc/fstab * * @param diskInfos */ static void set_preferred_disks(std::vector &diskInfos) { FILE *fstabFile = setmntent("/etc/fstab", "r"); if (fstabFile == nullptr) { /*fstab not accessible*/ return; } struct mntent *ent; while (nullptr != (ent = getmntent(fstabFile))) { bool found = false; for (auto disk_info : diskInfos) { if (strcmp(ent->mnt_fsname, disk_info.device) == 0) { disk_info.preferred = true; break; } } } endmntent(fstabFile); return; } /** * First try to read disk_infos from /dev/disk/by-id folder, if fails try to use * blkid cache to see what's in there, then try to exclude removable disks * looking at /etc/fstab * @param diskInfos_out vector used to output the disk informations * @return */ FUNCTION_RETURN getDiskInfos(std::vector &disk_infos) { FUNCTION_RETURN result = getDiskInfos_dev(disk_infos); if (result != FUNCTION_RETURN::FUNC_RET_OK) { result = getDiskInfos_blkid(disk_infos); } if (result == FUNCTION_RETURN::FUNC_RET_OK) { set_preferred_disks(disk_infos); } return result; } FUNCTION_RETURN getMachineName(unsigned char identifier[6]) { static struct utsname u; if (uname(&u) < 0) { return FUNC_RET_ERROR; } memcpy(identifier, u.nodename, 6); return FUNC_RET_OK; } FUNCTION_RETURN getOsSpecificIdentifier(unsigned char identifier[6]) { #if USE_DBUS char *dbus_id = dbus_get_local_machine_id(); if (dbus_id == NULL) { return FUNC_RET_ERROR; } memcpy(identifier, dbus_id, 6); dbus_free(dbus_id); return FUNC_RET_OK; #else return FUNC_RET_NOT_AVAIL; #endif } FUNCTION_RETURN getModuleName(char buffer[MAX_PATH]) { FUNCTION_RETURN result; char path[MAX_PATH] = {0}; char proc_path[MAX_PATH], pidStr[64]; pid_t pid = getpid(); sprintf(pidStr, "%d", pid); strcpy(proc_path, "/proc/"); strcat(proc_path, pidStr); strcat(proc_path, "/exe"); int ch = readlink(proc_path, path, MAX_PATH - 1); if (ch != -1) { path[ch] = '\0'; strncpy(buffer, path, ch); result = FUNC_RET_OK; } else { result = FUNC_RET_ERROR; } return result; }