diff options
| author | Peter Schiffer <pschiffe@redhat.com> | 2013-11-15 15:01:04 +0100 |
|---|---|---|
| committer | Peter Schiffer <pschiffe@redhat.com> | 2013-11-18 14:25:32 +0100 |
| commit | de7e807310e00883ae39c59cc9cd14a66eaa4586 (patch) | |
| tree | 4d1dffb9efb5d2fb64cb10a083150ed6fef927e7 /src/hardware | |
| parent | 2a6a28e5c8ee57b2adbb431370d6066d01df6719 (diff) | |
| download | openlmi-providers-de7e807310e00883ae39c59cc9cd14a66eaa4586.tar.gz openlmi-providers-de7e807310e00883ae39c59cc9cd14a66eaa4586.tar.xz openlmi-providers-de7e807310e00883ae39c59cc9cd14a66eaa4586.zip | |
Hardware: added lsblk fallback for physical disks
Smartctl doesn't work in virtual machine environment. Lsblk program reads sysfs
filesystem and outputs data about block devices. Advantage in using lsblk
instead of reading sysfs is, that it's not easy to distinguish between cd-roms,
disks, partitions, lvm.. Lsblk is doing some magic when determining the type of
device, so instead of duplicating the code, I'm using it's output. Lsblk is part
of the util-linux package, so no new dependency was introduced.
Diffstat (limited to 'src/hardware')
| -rw-r--r-- | src/hardware/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/hardware/LMI_DiskPhysicalPackageProvider.c | 66 | ||||
| -rw-r--r-- | src/hardware/lsblk.c | 218 | ||||
| -rw-r--r-- | src/hardware/lsblk.h | 55 | ||||
| -rw-r--r-- | src/hardware/smartctl.c | 4 | ||||
| -rw-r--r-- | src/hardware/utils.c | 24 | ||||
| -rw-r--r-- | src/hardware/utils.h | 12 |
7 files changed, 360 insertions, 20 deletions
diff --git a/src/hardware/CMakeLists.txt b/src/hardware/CMakeLists.txt index e75fde2..2d3512b 100644 --- a/src/hardware/CMakeLists.txt +++ b/src/hardware/CMakeLists.txt @@ -11,6 +11,7 @@ set(provider_SRCS sysfs.c PCIDev.c smartctl.c + lsblk.c ) konkretcmpi_generate(${MOF} diff --git a/src/hardware/LMI_DiskPhysicalPackageProvider.c b/src/hardware/LMI_DiskPhysicalPackageProvider.c index a2945f1..daa0133 100644 --- a/src/hardware/LMI_DiskPhysicalPackageProvider.c +++ b/src/hardware/LMI_DiskPhysicalPackageProvider.c @@ -23,6 +23,7 @@ #include "LMI_Hardware.h" #include "globals.h" #include "smartctl.h" +#include "lsblk.h" static const CMPIBroker* _cb = NULL; @@ -57,38 +58,68 @@ static CMPIStatus LMI_DiskPhysicalPackageEnumInstances( { LMI_DiskPhysicalPackage lmi_hdd; const char *ns = KNameSpace(cop); - unsigned i; - char instance_id[INSTANCE_ID_LEN]; + unsigned i, hdds_nb = 0; + char instance_id[INSTANCE_ID_LEN], *id, *manufacturer, *serial_nb, + *name, *model; SmartctlHdd *smtcl_hdds = NULL; unsigned smtcl_hdds_nb = 0; + LsblkHdd *lsblk_hdds = NULL; + unsigned lsblk_hdds_nb = 0; if (smartctl_get_hdds(&smtcl_hdds, &smtcl_hdds_nb) != 0 || smtcl_hdds_nb < 1) { - goto done; + smartctl_free_hdds(&smtcl_hdds, &smtcl_hdds_nb); + if (lsblk_get_hdds(&lsblk_hdds, &lsblk_hdds_nb) != 0 || lsblk_hdds_nb < 1) { + goto done; + } } - for (i = 0; i < smtcl_hdds_nb; i++) { + if (smtcl_hdds_nb > 0) { + hdds_nb = smtcl_hdds_nb; + } else { + hdds_nb = lsblk_hdds_nb; + } + + for (i = 0; i < hdds_nb; i++) { + /* in fallback mode, use only disk devices from lsblk */ + if (smtcl_hdds_nb < 1) { + if (strcmp(lsblk_hdds[i].type, "disk") != 0) { + continue; + } + } + + if (smtcl_hdds_nb > 0) { + id = smtcl_hdds[i].serial_number; + manufacturer = smtcl_hdds[i].manufacturer; + model = smtcl_hdds[i].model; + serial_nb = smtcl_hdds[i].serial_number; + name = smtcl_hdds[i].name; + } else { + id = lsblk_hdds[i].name; + manufacturer = lsblk_hdds[i].vendor; + model = lsblk_hdds[i].model; + serial_nb = lsblk_hdds[i].serial; + name = lsblk_hdds[i].name; + } + LMI_DiskPhysicalPackage_Init(&lmi_hdd, _cb, ns); LMI_DiskPhysicalPackage_Set_CreationClassName(&lmi_hdd, ORGID "_" DISK_PHYS_PKG_CLASS_NAME); LMI_DiskPhysicalPackage_Set_PackageType(&lmi_hdd, LMI_DiskPhysicalPackage_PackageType_Storage_Media_Package_e_g___Disk_or_Tape_Drive); - - snprintf(instance_id, INSTANCE_ID_LEN, - ORGID ":" ORGID "_" DISK_PHYS_PKG_CLASS_NAME ":%s", - smtcl_hdds[i].serial_number); - - LMI_DiskPhysicalPackage_Set_Tag(&lmi_hdd, smtcl_hdds[i].serial_number); - LMI_DiskPhysicalPackage_Set_Manufacturer(&lmi_hdd, - smtcl_hdds[i].manufacturer); - LMI_DiskPhysicalPackage_Set_Model(&lmi_hdd, smtcl_hdds[i].model); - LMI_DiskPhysicalPackage_Set_SerialNumber(&lmi_hdd, - smtcl_hdds[i].serial_number); LMI_DiskPhysicalPackage_Set_Caption(&lmi_hdd, "Physical Disk Package"); LMI_DiskPhysicalPackage_Set_Description(&lmi_hdd, "This object represents one physical disk package in system."); - LMI_DiskPhysicalPackage_Set_Name(&lmi_hdd, smtcl_hdds[i].name); - LMI_DiskPhysicalPackage_Set_ElementName(&lmi_hdd, smtcl_hdds[i].name); + + snprintf(instance_id, INSTANCE_ID_LEN, + ORGID ":" ORGID "_" DISK_PHYS_PKG_CLASS_NAME ":%s", id); + + LMI_DiskPhysicalPackage_Set_Tag(&lmi_hdd, id); + LMI_DiskPhysicalPackage_Set_Manufacturer(&lmi_hdd, manufacturer); + LMI_DiskPhysicalPackage_Set_Model(&lmi_hdd, model); + LMI_DiskPhysicalPackage_Set_SerialNumber(&lmi_hdd, serial_nb); + LMI_DiskPhysicalPackage_Set_Name(&lmi_hdd, name); + LMI_DiskPhysicalPackage_Set_ElementName(&lmi_hdd, name); LMI_DiskPhysicalPackage_Set_InstanceID(&lmi_hdd, instance_id); KReturnInstance(cr, lmi_hdd); @@ -96,6 +127,7 @@ static CMPIStatus LMI_DiskPhysicalPackageEnumInstances( done: smartctl_free_hdds(&smtcl_hdds, &smtcl_hdds_nb); + lsblk_free_hdds(&lsblk_hdds, &lsblk_hdds_nb); CMReturn(CMPI_RC_OK); } diff --git a/src/hardware/lsblk.c b/src/hardware/lsblk.c new file mode 100644 index 0000000..74d4a2f --- /dev/null +++ b/src/hardware/lsblk.c @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Peter Schiffer <pschiffe@redhat.com> + */ + +#include "lsblk.h" + +/* + * Initialize LsblkHdd attributes. + * @param hdd + */ +void init_lsblkhdd_struct(LsblkHdd *hdd) +{ + hdd->name = NULL; + hdd->basename = NULL; + hdd->type = NULL; + hdd->model = NULL; + hdd->serial = NULL; + hdd->revision = NULL; + hdd->vendor = NULL; +} + +/* + * Check attributes of hdd structure and fill in defaults if needed. + * @param hdd + * @return 0 if success, negative value otherwise + */ +short check_lsblkhdd_attributes(LsblkHdd *hdd) +{ + short ret = -1; + + if (!hdd->name) { + if (!(hdd->name = strdup(""))) { + goto done; + } + } + if (!hdd->basename) { + if (!(hdd->basename = strdup(""))) { + goto done; + } + } + if (!hdd->type) { + if (!(hdd->type = strdup(""))) { + goto done; + } + } + if (!hdd->model) { + if (!(hdd->model = strdup(""))) { + goto done; + } + } + if (!hdd->serial) { + if (!(hdd->serial = strdup(""))) { + goto done; + } + } + if (!hdd->revision) { + if (!(hdd->revision = strdup(""))) { + goto done; + } + } + if (!hdd->vendor) { + if (!(hdd->vendor = strdup(""))) { + goto done; + } + } + + ret = 0; + +done: + if (ret != 0) { + warn("Failed to allocate memory."); + } + + return ret; +} + +short lsblk_get_hdds(LsblkHdd **hdds, unsigned *hdds_nb) +{ + short ret = -1; + unsigned i, curr_hdd = 0, buffer_size = 0; + char **buffer = NULL, *path, *type; + struct stat sb; + + lsblk_free_hdds(hdds, hdds_nb); + + /* get lsblk output */ + if (run_command("lsblk -dPpo NAME,TYPE,MODEL,SERIAL,REV,VENDOR", + &buffer, &buffer_size) != 0) { + goto done; + } + + /* count hard drives - one line of output is one device */ + *hdds_nb = buffer_size; + + /* if no hard drive was found */ + if (*hdds_nb < 1) { + warn("Lsblk didn't recognize any hard drive."); + goto done; + } + + /* allocate memory for hard drives */ + *hdds = (LsblkHdd *)calloc(*hdds_nb, sizeof(LsblkHdd)); + if (!(*hdds)) { + warn("Failed to allocate memory."); + *hdds_nb = 0; + goto done; + } + + /* parse information about hard drives */ + for (i = 0; i < buffer_size; i++) { + path = get_part_of_string_between(buffer[i], "NAME=\"", "\""); + if (!path) { + continue; + } + if (stat(path, &sb) != 0) { + warn("Stat() call on file \"%s\" failed: %s", + path, strerror(errno)); + free(path); + continue; + } + if ((sb.st_mode & S_IFMT) != S_IFBLK) { + warn("File \"%s\" is not a block device.", path); + free(path); + continue; + } + + type = get_part_of_string_between(buffer[i], "TYPE=\"", "\""); + if (!type) { + free(path); + continue; + } + + init_lsblkhdd_struct(&(*hdds)[curr_hdd]); + + (*hdds)[curr_hdd].name = path; + (*hdds)[curr_hdd].type = type; + (*hdds)[curr_hdd].model = get_part_of_string_between(buffer[i], "MODEL=\"", "\""); + (*hdds)[curr_hdd].serial = get_part_of_string_between(buffer[i], "SERIAL=\"", "\""); + (*hdds)[curr_hdd].revision = get_part_of_string_between(buffer[i], "REV=\"", "\""); + (*hdds)[curr_hdd].vendor = get_part_of_string_between(buffer[i], "VENDOR=\"", "\""); + + curr_hdd++; + } + + if (curr_hdd != *hdds_nb) { + warn("Not all reported drives by lsblk were processed."); + LsblkHdd *tmp_hdd = (LsblkHdd *)realloc(*hdds, + curr_hdd * sizeof(LsblkHdd)); + if (!tmp_hdd) { + warn("Failed to allocate memory."); + goto done; + } + *hdds = tmp_hdd; + *hdds_nb = curr_hdd; + } + + /* fill in default attributes if needed */ + for (i = 0; i < *hdds_nb; i++) { + if (check_lsblkhdd_attributes(&(*hdds)[i]) != 0) { + goto done; + } + } + + ret = 0; + +done: + free_2d_buffer(&buffer, &buffer_size); + + if (ret != 0) { + lsblk_free_hdds(hdds, hdds_nb); + } + + return ret; +} + +void lsblk_free_hdds(LsblkHdd **hdds, unsigned *hdds_nb) +{ + unsigned i; + + if (*hdds && *hdds_nb > 0) { + for (i = 0; i < *hdds_nb; i++) { + free((*hdds)[i].name); + (*hdds)[i].name = NULL; + free((*hdds)[i].basename); + (*hdds)[i].basename = NULL; + free((*hdds)[i].type); + (*hdds)[i].type = NULL; + free((*hdds)[i].model); + (*hdds)[i].model = NULL; + free((*hdds)[i].serial); + (*hdds)[i].serial = NULL; + free((*hdds)[i].revision); + (*hdds)[i].revision = NULL; + free((*hdds)[i].vendor); + (*hdds)[i].vendor = NULL; + } + free(*hdds); + } + + *hdds_nb = 0; + *hdds = NULL; +} diff --git a/src/hardware/lsblk.h b/src/hardware/lsblk.h new file mode 100644 index 0000000..b41207b --- /dev/null +++ b/src/hardware/lsblk.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Peter Schiffer <pschiffe@redhat.com> + */ + +#ifndef LSBLK_H_ +#define LSBLK_H_ + +#include <sys/types.h> +#include <sys/stat.h> +#include "utils.h" + +/* Disk by lsblk program. */ +typedef struct _LsblkHdd { + char *name; /* /dev/path as name */ + char *basename; /* Basename of /dev/path */ + char *type; /* Disk type; disk for disk, rom for cdrom */ + char *model; /* Model */ + char *serial; /* Serial number */ + char *revision; /* Revision */ + char *vendor; /* Vendor */ +} LsblkHdd; + +/* + * Get array of disks from sysfs by lsblk program. + * @param hdds array of disks, this function will allocate necessary + * memory, but caller is responsible for freeing it + * @param hdds_nb number of disks in hdds + * @return 0 if success, negative value otherwise + */ +short lsblk_get_hdds(LsblkHdd **hdds, unsigned *hdds_nb); + +/* + * Free array of disks. + * @param hdds array of disks + * @param hdds_nb number of disks in hdds + */ +void lsblk_free_hdds(LsblkHdd **hdds, unsigned *hdds_nb); + +#endif /* LSBLK_H_ */ diff --git a/src/hardware/smartctl.c b/src/hardware/smartctl.c index 750dea6..8ba724a 100644 --- a/src/hardware/smartctl.c +++ b/src/hardware/smartctl.c @@ -117,8 +117,6 @@ short scan_smctlhdd_devices(SmartctlHdd **hdds, unsigned *hdds_nb) /* parse hard drive's dev path */ for (i = 0; i < buffer_size; i++) { - init_smctlhdd_struct(&(*hdds)[i]); - if (explode(buffer[i], NULL, &sec_buffer, &sec_buffer_size) != 0 || sec_buffer_size < 1) { free_2d_buffer(&sec_buffer, &sec_buffer_size); @@ -138,6 +136,8 @@ short scan_smctlhdd_devices(SmartctlHdd **hdds, unsigned *hdds_nb) continue; } + init_smctlhdd_struct(&(*hdds)[curr_hdd]); + (*hdds)[curr_hdd].dev_path = strdup(sec_buffer[0]); (*hdds)[curr_hdd].dev_basename = strdup(basename(sec_buffer[0])); if (!(*hdds)[curr_hdd].dev_path || !(*hdds)[curr_hdd].dev_basename) { diff --git a/src/hardware/utils.c b/src/hardware/utils.c index 20d9fca..2393d66 100644 --- a/src/hardware/utils.c +++ b/src/hardware/utils.c @@ -409,3 +409,27 @@ char *append_str(char *str, ...) return str; } + +char *get_part_of_string_between(const char *str, const char *after, const char *until) +{ + char *temp = NULL, *end_pos = NULL, *out = NULL; + + if (!str || strlen(str) < 1 || !after || strlen(after) < 1) { + return NULL; + } + + temp = copy_string_part_after_delim(str, after); + if (!temp) { + return NULL; + } + + end_pos = strstr(temp, until); + if (!end_pos) { + return temp; + } + + end_pos[0] = '\0'; + out = trim(temp, NULL); + free (temp); + return out; +} diff --git a/src/hardware/utils.h b/src/hardware/utils.h index 2a1a690..abd67d4 100644 --- a/src/hardware/utils.h +++ b/src/hardware/utils.h @@ -28,7 +28,7 @@ #include <stdarg.h> #include "globals.h" -#define LONG_INT_LEN 21 /* 64 bit unsigned int can has 20 decimals + \0 */ +#define LONG_INT_LEN 21 /* 64 bit unsigned int can have 20 decimals + \0 */ #define WHITESPACES " \f\n\r\t\v" @@ -120,5 +120,15 @@ short explode(const char *str, const char *delims, char ***buffer, unsigned *buf */ char *append_str(char *str, ...); +/* + * Return part of the string following string in after param and ending before + * string in until param. + * @param str input string + * @param after left boundary of returned string + * @param until right boundary of returned string + * @return trimmed string allocated with malloc or NULL if allocation failed + * or string wasn't found + */ +char *get_part_of_string_between(const char *str, const char *after, const char *until); #endif /* UTILS_H_ */ |
