From 7a0b251bcd55a26679bb99480f02948105947d05 Mon Sep 17 00:00:00 2001 From: Peter Schiffer Date: Wed, 6 Mar 2013 13:16:25 +0100 Subject: Created LMI_ProcessorProvider providing basic information about CPU. Main source of information is dmidecode program, with additional information from lscpu program and /proc/cpuinfo file. If no output from dmidecode program is available, fallback with only lscpu and /proc/cpuinfo is used. --- src/hardware/CMakeLists.txt | 11 +- src/hardware/LMI_ProcessorProvider.c | 1153 ++++++++++++++++++++++++++++++++++ src/hardware/cpuinfo.c | 145 +++++ src/hardware/cpuinfo.h | 54 ++ src/hardware/dmidecode.c | 343 ++++++++++ src/hardware/dmidecode.h | 66 ++ src/hardware/lscpu.c | 151 +++++ src/hardware/lscpu.h | 55 ++ src/hardware/utils.c | 382 +++++++++++ src/hardware/utils.h | 111 ++++ 10 files changed, 2467 insertions(+), 4 deletions(-) create mode 100644 src/hardware/LMI_ProcessorProvider.c create mode 100644 src/hardware/cpuinfo.c create mode 100644 src/hardware/cpuinfo.h create mode 100644 src/hardware/dmidecode.c create mode 100644 src/hardware/dmidecode.h create mode 100644 src/hardware/lscpu.c create mode 100644 src/hardware/lscpu.h create mode 100644 src/hardware/utils.c create mode 100644 src/hardware/utils.h (limited to 'src/hardware') diff --git a/src/hardware/CMakeLists.txt b/src/hardware/CMakeLists.txt index 27e8df2..ebf79fb 100644 --- a/src/hardware/CMakeLists.txt +++ b/src/hardware/CMakeLists.txt @@ -1,11 +1,14 @@ - set(PROVIDER_NAME Hardware) set(LIBRARY_NAME cmpiLMI_${PROVIDER_NAME}) set(MOF LMI_Hardware.mof) -#set(provider_SRCS -# util/serviceutil.c -#) +set(provider_SRCS + utils.c + dmidecode.c + lscpu.c + cpuinfo.c + LMI_ProcessorProvider.c +) konkretcmpi_generate(${MOF} CIM_PROVIDERS diff --git a/src/hardware/LMI_ProcessorProvider.c b/src/hardware/LMI_ProcessorProvider.c new file mode 100644 index 0000000..8e92fdd --- /dev/null +++ b/src/hardware/LMI_ProcessorProvider.c @@ -0,0 +1,1153 @@ +/* + * 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 + */ + +#include +#include +#include +#include "LMI_Processor.h" +#include "globals.h" +#include "dmidecode.h" +#include "lscpu.h" +#include "cpuinfo.h" + +CMPIUint16 get_family(const char *family); +CMPIUint16 get_cpustatus(const char *status); +CMPIUint16 get_enabledstate(const CMPIUint16 status); +CMPIUint16 get_upgrade_method(const char *dmi_upgrade); +CMPIUint16 get_characteristic(const char *dmi_charact); +CMPIUint16 get_flag(const char *flag, short *stat); + +static const CMPIBroker* _cb = NULL; + +static void LMI_ProcessorInitialize() +{ +} + +static CMPIStatus LMI_ProcessorCleanup( + CMPIInstanceMI* mi, + const CMPIContext* cc, + CMPIBoolean term) +{ + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_ProcessorEnumInstanceNames( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop) +{ + return KDefaultEnumerateInstanceNames( + _cb, mi, cc, cr, cop); +} + +static CMPIStatus LMI_ProcessorEnumInstances( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char** properties) +{ + LMI_Processor lmi_cpu; + const char *ns = KNameSpace(cop); + CMPICount count; + CMPIUint16 cpustatus, enabledstate, family, charact, enabled_cores; + CMPIUint32 current_speed = 0, max_speed = 0, external_clock = 0; + unsigned i, j, cpus_nb = 0; + char *other_family = NULL, *architecture = NULL, *cpu_id = NULL, + *cpu_name = NULL, *stepping = NULL, *error_msg = NULL; + struct utsname utsname_buf; + DmiProcessor *dmi_cpus; + unsigned dmi_cpus_nb; + LscpuProcessor lscpu; + CpuinfoProcessor proc_cpu; + + if (dmi_get_processors(&dmi_cpus, &dmi_cpus_nb) != 0 || dmi_cpus_nb < 1) { + dmi_free_processors(&dmi_cpus, &dmi_cpus_nb); + } + + if (lscpu_get_processor(&lscpu) != 0) { + error_msg = "Unable to get processor information."; + goto done; + } + + if (cpuinfo_get_processor(&proc_cpu) != 0) { + error_msg = "Unable to get processor information."; + goto done; + } + + if (uname(&utsname_buf) == 0) { + architecture = strdup(utsname_buf.machine); + if (!architecture) { + error_msg = "Not enough available memory."; + goto done; + } + } + + if (dmi_cpus_nb > 0) { + cpus_nb = dmi_cpus_nb; + } else if (lscpu.processors > 0) { + cpus_nb = lscpu.processors; + } else { + error_msg = "Unable to get processor information."; + goto done; + } + + for (i = 0; i < cpus_nb; i++) { + LMI_Processor_Init(&lmi_cpu, _cb, ns); + + LMI_Processor_Set_SystemCreationClassName(&lmi_cpu, + get_system_creation_class_name()); + LMI_Processor_Set_SystemName(&lmi_cpu, get_system_name()); + LMI_Processor_Set_CreationClassName(&lmi_cpu, "LMI_Processor"); + LMI_Processor_Set_Caption(&lmi_cpu, "Processor"); + LMI_Processor_Set_Description(&lmi_cpu, + "This object represents one processor in system."); + + /* do we have output from dmidecode program? */ + if (dmi_cpus_nb > 0) { + family = get_family(dmi_cpus[i].family); + if (family == 1) { + other_family = dmi_cpus[i].family; + } + cpustatus = get_cpustatus(dmi_cpus[i].status); + enabledstate = get_enabledstate(cpustatus); + if (enabledstate == 2) { + current_speed = dmi_cpus[i].current_speed; + max_speed = dmi_cpus[i].max_speed; + external_clock = dmi_cpus[i].external_clock; + } + cpu_name = dmi_cpus[i].name; + enabled_cores = dmi_cpus[i].enabled_cores; + stepping = dmi_cpus[i].stepping; + + LMI_Processor_Set_DeviceID(&lmi_cpu, dmi_cpus[i].id); + LMI_Processor_Set_Family(&lmi_cpu, family); + LMI_Processor_Set_OtherFamilyDescription(&lmi_cpu, other_family); + LMI_Processor_Set_UpgradeMethod(&lmi_cpu, + get_upgrade_method(dmi_cpus[i].upgrade)); + if (dmi_cpus[i].type && strlen(dmi_cpus[i].type)) { + LMI_Processor_Set_Role(&lmi_cpu, dmi_cpus[i].type); + } + /* CPU Characteristics */ + if (dmi_cpus[i].charact_nb > 0) { + count = 0; + LMI_Processor_Init_Characteristics(&lmi_cpu, + dmi_cpus[i].charact_nb); + LMI_Processor_Init_EnabledProcessorCharacteristics(&lmi_cpu, + dmi_cpus[i].charact_nb); + for (j = 0; j < dmi_cpus[i].charact_nb; j++) { + charact = get_characteristic( + dmi_cpus[i].characteristics[j]); + if (charact) { + LMI_Processor_Set_Characteristics(&lmi_cpu, count, + charact); + LMI_Processor_Set_EnabledProcessorCharacteristics( + &lmi_cpu, count, 0); + count++; + } + } + } + } else { + cpu_id = (char *)malloc(10 * sizeof(char)); + if (!cpu_id) { + error_msg = "Not enough available memory."; + goto done; + } + snprintf(cpu_id, 10, "%u", i); + LMI_Processor_Set_DeviceID(&lmi_cpu, cpu_id); + free(cpu_id); + cpu_id = NULL; + + cpustatus = get_cpustatus("Enabled"); + enabledstate = get_enabledstate(cpustatus); + if (enabledstate == 2) { + current_speed = lscpu.current_speed; + } + + cpu_name = proc_cpu.model_name; + enabled_cores = lscpu.cores; + stepping = lscpu.stepping; + } + + LMI_Processor_Set_CPUStatus(&lmi_cpu, cpustatus); + LMI_Processor_Set_EnabledState(&lmi_cpu, enabledstate); + LMI_Processor_Set_NumberOfEnabledCores(&lmi_cpu, enabled_cores); + if (current_speed) { + LMI_Processor_Set_CurrentClockSpeed(&lmi_cpu, current_speed); + } + if (max_speed) { + LMI_Processor_Set_MaxClockSpeed(&lmi_cpu, max_speed); + } + if (external_clock) { + LMI_Processor_Set_ExternalBusClockSpeed(&lmi_cpu, external_clock); + } + if (cpu_name && strlen(cpu_name)) { + LMI_Processor_Set_Name(&lmi_cpu, cpu_name); + LMI_Processor_Set_UniqueID(&lmi_cpu, cpu_name); + LMI_Processor_Set_ElementName(&lmi_cpu, cpu_name); + } + if (stepping && strlen(stepping)) { + LMI_Processor_Set_Stepping(&lmi_cpu, stepping); + } + if (lscpu.data_width) { + LMI_Processor_Set_DataWidth(&lmi_cpu, lscpu.data_width); + } + /* CPU Flags */ + if (proc_cpu.flags_nb > 0) { + short stat = -1; + CMPIUint16 flag; + LMI_Processor_Init_Flags(&lmi_cpu, proc_cpu.flags_nb); + count = 0; + for (j = 0; j < proc_cpu.flags_nb; j++) { + flag = get_flag(proc_cpu.flags[j], &stat); + if (stat == 0) { + LMI_Processor_Set_Flags(&lmi_cpu, count, flag); + count++; + } + } + } + if (proc_cpu.address_size) { + LMI_Processor_Set_AddressWidth(&lmi_cpu, proc_cpu.address_size); + } + if (architecture && strlen(architecture)) { + LMI_Processor_Set_Architecture(&lmi_cpu, architecture); + } + + KReturnInstance(cr, lmi_cpu); + } + +done: + if (architecture) { + free(architecture); + } + architecture = NULL; + + dmi_free_processors(&dmi_cpus, &dmi_cpus_nb); + lscpu_free_processor(&lscpu); + cpuinfo_free_processor(&proc_cpu); + + if (error_msg) { + KReturn2(_cb, ERR_FAILED, error_msg); + } + + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_ProcessorGetInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char** properties) +{ + return KDefaultGetInstance( + _cb, mi, cc, cr, cop, properties); +} + +static CMPIStatus LMI_ProcessorCreateInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const CMPIInstance* ci) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_ProcessorModifyInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const CMPIInstance* ci, + const char** properties) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_ProcessorDeleteInstance( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_ProcessorExecQuery( + CMPIInstanceMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* lang, + const char* query) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +CMInstanceMIStub( + LMI_Processor, + LMI_Processor, + _cb, + LMI_ProcessorInitialize()) + +static CMPIStatus LMI_ProcessorMethodCleanup( + CMPIMethodMI* mi, + const CMPIContext* cc, + CMPIBoolean term) +{ + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_ProcessorInvokeMethod( + CMPIMethodMI* mi, + const CMPIContext* cc, + const CMPIResult* cr, + const CMPIObjectPath* cop, + const char* meth, + const CMPIArgs* in, + CMPIArgs* out) +{ + return LMI_Processor_DispatchMethod( + _cb, mi, cc, cr, cop, meth, in, out); +} + +CMMethodMIStub( + LMI_Processor, + LMI_Processor, + _cb, + LMI_ProcessorInitialize()) + +KUint32 LMI_Processor_RequestStateChange( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_ProcessorRef* self, + const KUint16* RequestedState, + KRef* Job, + const KDateTime* TimeoutPeriod, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KUint32 LMI_Processor_SetPowerState( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_ProcessorRef* self, + const KUint16* PowerState, + const KDateTime* Time, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KUint32 LMI_Processor_Reset( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_ProcessorRef* self, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KUint32 LMI_Processor_EnableDevice( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_ProcessorRef* self, + const KBoolean* Enabled, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KUint32 LMI_Processor_OnlineDevice( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_ProcessorRef* self, + const KBoolean* Online, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KUint32 LMI_Processor_QuiesceDevice( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_ProcessorRef* self, + const KBoolean* Quiesce, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KUint32 LMI_Processor_SaveProperties( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_ProcessorRef* self, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +KUint32 LMI_Processor_RestoreProperties( + const CMPIBroker* cb, + CMPIMethodMI* mi, + const CMPIContext* context, + const LMI_ProcessorRef* self, + CMPIStatus* status) +{ + KUint32 result = KUINT32_INIT; + + KSetStatus(status, ERR_NOT_SUPPORTED); + return result; +} + +/* + * Get CPU status according to the dmidecode. + * @param status from dmidecode + * @return CIM id of CPU status + */ +CMPIUint16 get_cpustatus(const char *status) +{ + if (!status) { + return 0; /* Unknown */ + } + + static struct { + CMPIUint16 val; /* CIM value */ + char *stat; /* dmidecode status */ + } statuses[] = { + {0, "Unknown"}, + {1, "Enabled"}, + {2, "Disabled By User"}, + {3, "Disabled By BIOS"}, + {4, "Idle"}, + }; + + size_t i, st_length = sizeof(statuses) / sizeof(statuses[0]); + + for (i = 0; i < st_length; i++) { + if (strcmp(status, statuses[i].stat) == 0) { + return statuses[i].val; + } + } + + return 0; /* Unknown */ +} + +/* + * Get enabled state according to the cpu status. + * @param status by CIM + * @return CIM id of enabled state + */ +CMPIUint16 get_enabledstate(const CMPIUint16 status) +{ + static struct { + CMPIUint16 cpustatus; /* CIM cpu status */ + CMPIUint16 enabledstate; /* CIM enabled state */ + } statuses[] = { + {0, 0}, + {1, 2}, + {2, 3}, + {3, 3}, + {4, 2}, + }; + + size_t i, st_length = sizeof(statuses) / sizeof(statuses[0]); + + for (i = 0; i < st_length; i++) { + if (status == statuses[i].cpustatus) { + return statuses[i].enabledstate; + } + } + + return 0; /* Unknown */ +} + +/* + * Get CPU characteristics according to the dmidecode output. + * @param dmi_charact characteristics from dmidecode + * @return characteristic defined by CIM + */ +CMPIUint16 get_characteristic(const char *dmi_charact) +{ + if (!dmi_charact) { + return 0; /* Unknown */ + } + + /* CIM characteristics based on + cim_schema_2.35.0Final-MOFs/Device/CIM_Processor.mof */ + /* Dmidecode characts based on dmidecode 2.11 */ + static struct { + CMPIUint16 value_map; /* ValueMap defined by CIM */ + char *value; /* Value defined by CIM (just for reference) */ + char *search; /* String used to match the dmidecode charact */ + } characts[] = { + /* + {0, "Unknown", ""}, + {1, "DMTF Reserved", ""}, + */ + {2, "64-bit Capable", "64-bit capable"}, + /* + {3, "32-bit Capable", ""}, + */ + {4, "Enhanced Virtualization", "Enhanced Virtualization"}, + {5, "Hardware Thread", "Hardware Thread"}, + {6, "NX-bit", "Execute Protection"}, + {7, "Power/Performance Control", "Power/Performance Control"}, + /* + {8, "Core Frequency Boosting", ""}, + */ + {32568, "Multi-Core", "Multi-Core"}, + }; + + size_t i, characts_length = sizeof(characts) / sizeof(characts[0]); + + for (i = 0; i < characts_length; i++) { + if (strcmp(dmi_charact, characts[i].search) == 0) { + return characts[i].value_map; + } + } + + return 0; /* Unknown */ +} + +/* + * Get CPU upgrade method according to the dmidecode upgrade. + * @param dmi_upgrade socket string from dmidecode program + * @return upgrade method id defined by CIM + */ +CMPIUint16 get_upgrade_method(const char *dmi_upgrade) +{ + if (!dmi_upgrade) { + return 2; /* Unknown */ + } + + /* CIM upgrade method based on + cim_schema_2.35.0Final-MOFs/Device/CIM_Processor.mof */ + /* Dmidecode upgrade based on dmidecode 2.11 */ + static struct { + CMPIUint16 value_map; /* ValueMap defined by CIM */ + char *value; /* Value defined by CIM (just for reference) */ + char *search; /* String used to match the dmidecode upgrade */ + } sockets[] = { + {1, "Other", "Other"}, + {2, "Unknown", "Unknown"}, + {3, "Daughter Board", "Daughter Board"}, + {4, "ZIF Socket", "ZIF Socket"}, + {5, "Replacement/Piggy Back", "Replaceable Piggy Back"}, + {6, "None", "None"}, + {7, "LIF Socket", "LIF Socket"}, + {8, "Slot 1", "Slot 1"}, + {9, "Slot 2", "Slot 2"}, + {10, "370 Pin Socket", "370-pin Socket"}, + {11, "Slot A", "Slot A"}, + {12, "Slot M", "Slot M"}, + {13, "Socket 423", "Socket 423"}, + {14, "Socket A (Socket 462)", "Socket A (Socket 462)"}, + {15, "Socket 478", "Socket 478"}, + {16, "Socket 754", "Socket 754"}, + {17, "Socket 940", "Socket 940"}, + {18, "Socket 939", "Socket 939"}, + {19, "Socket mPGA604", "Socket mPGA604"}, + {20, "Socket LGA771", "Socket LGA771"}, + {21, "Socket LGA775", "Socket LGA775"}, + {22, "Socket S1", "Socket S1"}, + {23, "Socket AM2", "Socket AM2"}, + {24, "Socket F (1207)", "Socket F (1207)"}, + {25, "Socket LGA1366", "Socket LGA1366"}, + {26, "Socket G34", "Socket G34"}, + {27, "Socket AM3", "Socket AM3"}, + {28, "Socket C32", "Socket C32"}, + {29, "Socket LGA1156", "Socket LGA1156"}, + {30, "Socket LGA1567", "Socket LGA1567"}, + {31, "Socket PGA988A", "Socket PGA988A"}, + {32, "Socket BGA1288", "Socket BGA1288"}, + {33, "rPGA988B", "Socket rPGA988B"}, + {34, "BGA1023", "Socket BGA1023"}, + {35, "BGA1224", "Socket BGA1024"}, + {36, "LGA1155", "Socket BGA1155"}, + {37, "LGA1356", "Socket LGA1356"}, + {38, "LGA2011", "Socket LGA2011"}, + {39, "Socket FS1", "Socket FS1"}, + {40, "Socket FS2", "Socket FS2"}, + {41, "Socket FM1", "Socket FM1"}, + {42, "Socket FM2", "Socket FM2"}, + /* + {43, "Socket LGA2011-3", ""}, + {44, "Socket LGA1356-3", ""}, + */ + }; + + size_t i, sockets_length = sizeof(sockets) / sizeof(sockets[0]); + + for (i = 0; i < sockets_length; i++) { + if (strcmp(dmi_upgrade, sockets[i].search) == 0) { + return sockets[i].value_map; + } + } + + return 1; /* Other */ +} + +/* + * Get CPU flag id. + * @param flag from /proc/cpuinfo file + * @param stat 0 if flag found, negative value otherwise + * @return CIM id of flag + */ +CMPIUint16 get_flag(const char *flag, short *stat) +{ + if (!flag) { + *stat = -1; + return 0; + } + + /* Flag IDs and names are based on: + linux-3.8/arch/x86/include/asm/cpufeature.h */ + static struct { + CMPIUint16 val; /* CIM value */ + char *flag; /* flag name */ + } flags[] = { + /* 0*32 */ + {0, "fpu"}, + {1, "vme"}, + {2, "de"}, + {3, "pse"}, + {4, "tsc"}, + {5, "msr"}, + {6, "pae"}, + {7, "mce"}, + {8, "cx8"}, + {9, "apic"}, + {11, "sep"}, + {12, "mtrr"}, + {13, "pge"}, + {14, "mca"}, + {15, "cmov"}, + {16, "pat"}, + {17, "pse36"}, + {18, "pn"}, + {19, "clflush"}, + {21, "dts"}, + {22, "acpi"}, + {23, "mmx"}, + {24, "fxsr"}, + {25, "sse"}, + {26, "sse2"}, + {27, "ss"}, + {28, "ht"}, + {29, "tm"}, + {30, "ia64"}, + {31, "pbe"}, + /* 1*32 */ + {43, "syscall"}, + {51, "mp"}, + {52, "nx"}, + {54, "mmxext"}, + {57, "fxsr_opt"}, + {58, "pdpe1gb"}, + {59, "rdtscp"}, + {61, "lm"}, + {62, "3dnowext"}, + {63, "3dnow"}, + /* 2*32 */ + {64, "recovery"}, + {65, "longrun"}, + {67, "lrti"}, + /* 3*32 */ + {96, "cxmmx"}, + {97, "k6_mtrr"}, + {98, "cyrix_arr"}, + {99, "centaur_mcr"}, + {100, "k8"}, + {101, "k7"}, + {102, "p3"}, + {103, "p4"}, + {104, "constant_tsc"}, + {105, "up"}, + {106, "fxsave_leak"}, + {107, "arch_perfmon"}, + {108, "pebs"}, + {109, "bts"}, + {110, "syscall32"}, + {111, "sysenter32"}, + {112, "rep_good"}, + {113, "mfence_rdtsc"}, + {114, "lfence_rdtsc"}, + {115, "11ap"}, + {116, "nopl"}, + {118, "xtopology"}, + {119, "tsc_reliable"}, + {120, "nonstop_tsc"}, + {121, "clflush_monitor"}, + {122, "extd_apicid"}, + {123, "amd_dcm"}, + {124, "aperfmperf"}, + {125, "eagerfpu"}, + /* 4*32 */ + {128, "pni"}, + {129, "pclmulqdq"}, + {130, "dtes64"}, + {131, "monitor"}, + {132, "ds_cpl"}, + {133, "vmx"}, + {134, "smx"}, + {135, "est"}, + {136, "tm2"}, + {137, "ssse3"}, + {138, "cid"}, + {140, "fma"}, + {141, "cx16"}, + {142, "xtpr"}, + {143, "pdcm"}, + {145, "pcid"}, + {146, "dca"}, + {147, "sse4_1"}, + {148, "sse4_2"}, + {149, "x2apic"}, + {150, "movbe"}, + {151, "popcnt"}, + {152, "tsc_deadline_timer"}, + {153, "aes"}, + {154, "xsave"}, + {155, "osxsave"}, + {156, "avx"}, + {157, "f16c"}, + {158, "rdrand"}, + {159, "hypervisor"}, + /* 5*32*/ + {162, "rng"}, + {163, "rng_en"}, + {166, "ace"}, + {167, "ace_en"}, + {168, "ace2"}, + {169, "ace2_en"}, + {170, "phe"}, + {171, "phe_en"}, + {172, "pmm"}, + {173, "pmm_en"}, + /* 6*32 */ + {192, "lahf_lm"}, + {193, "cmp_legacy"}, + {194, "svm"}, + {195, "extapic"}, + {196, "cr8_legacy"}, + {197, "abm"}, + {198, "sse4a"}, + {199, "misalignsse"}, + {200, "3dnowprefetch"}, + {201, "osvw"}, + {202, "ibs"}, + {203, "xop"}, + {204, "skinit"}, + {205, "wdt"}, + {207, "lwp"}, + {208, "fma4"}, + {209, "tce"}, + {211, "nodeid_msr"}, + {213, "tbm"}, + {214, "topoext"}, + {215, "perfctr_core"}, + /* 7*32 */ + {224, "ida"}, + {225, "arat"}, + {226, "cpb"}, + {227, "epb"}, + {228, "xsaveopt"}, + {229, "pln"}, + {230, "pts"}, + {231, "dtherm"}, + {232, "hw_pstate"}, + /* 8*32 */ + {256, "tpr_shadow"}, + {257, "vnmi"}, + {258, "flexpriority"}, + {259, "ept"}, + {260, "vpid"}, + {261, "npt"}, + {262, "lbrv"}, + {263, "svm_lock"}, + {264, "nrip_save"}, + {265, "tsc_scale"}, + {266, "vmcb_clean"}, + {267, "flushbyasid"}, + {268, "decodeassists"}, + {269, "pausefilter"}, + {270, "pfthreshold"}, + /* 9*32 */ + {288, "fsgsbase"}, + {289, "tsc_adjust"}, + {291, "bmi1"}, + {292, "hle"}, + {293, "avx2"}, + {295, "smep"}, + {296, "bmi2"}, + {297, "erms"}, + {298, "invpcid"}, + {299, "rtm"}, + {306, "rdseed"}, + {307, "adx"}, + {308, "smap"}, + }; + + size_t i, st_length = sizeof(flags) / sizeof(flags[0]); + + for (i = 0; i < st_length; i++) { + if (strcmp(flag, flags[i].flag) == 0) { + *stat = 0; + return flags[i].val; + } + } + + *stat = -2; + return 0; +} + +/* + * Get CPU family id according to the dmidecode family. + * @param dmi_family family string from dmidecode program + * @return family id defined by CIM + */ +CMPIUint16 get_family(const char *dmi_family) +{ + if (!dmi_family) { + return 2; /* Unknown */ + } + + /* CIM CPU families based on + cim_schema_2.35.0Final-MOFs/Device/CIM_Processor.mof */ + /* Dmidecode families based on dmidecode 2.11 */ + static struct { + CMPIUint16 value_map; /* ValueMap defined by CIM */ + char *value; /* Value defined by CIM (just for reference) */ + char *search; /* String used to match the dmidecode family */ + } fm[] = { + {1, "Other", "Other"}, + {2, "Unknown", "Unknown"}, + {3, "8086", "8086"}, + {4, "80286", "80286"}, + {5, "80386", "80386"}, + {6, "80486", "80486"}, + {7, "8087", "8087"}, + {8, "80287", "80287"}, + {9, "80387", "80387"}, + {10, "80487", "80487"}, + {11, "Pentium(R) brand", "Pentium"}, + {12, "Pentium(R) Pro", "Pentium Pro"}, + {13, "Pentium(R) II", "Pentium II"}, + {14, "Pentium(R) processor with MMX(TM) technology", "Pentium MMX"}, + {15, "Celeron(TM)", "Celeron"}, + {16, "Pentium(R) II Xeon(TM)", "Pentium II Xeon"}, + {17, "Pentium(R) III", "Pentium III"}, + {18, "M1 Family", "M1"}, + {19, "M2 Family", "M2"}, + {20, "Intel(R) Celeron(R) M processor", "Celeron M"}, + {21, "Intel(R) Pentium(R) 4 HT processor", "Pentium 4 HT"}, + + {24, "K5 Family", "K5"}, + {25, "K6 Family", "K6"}, + {26, "K6-2", "K6-2"}, + {27, "K6-3", "K6-3"}, + {28, "AMD Athlon(TM) Processor Family", "Athlon"}, + {29, "AMD(R) Duron(TM) Processor", "Duron"}, + {30, "AMD29000 Family", "AMD29000"}, + {31, "K6-2+", "K6-2+"}, + {32, "Power PC Family", "Power PC"}, + {33, "Power PC 601", "Power PC 601"}, + {34, "Power PC 603", "Power PC 603"}, + {35, "Power PC 603+", "Power PC 603+"}, + {36, "Power PC 604", "Power PC 604"}, + {37, "Power PC 620", "Power PC 620"}, + {38, "Power PC X704", "Power PC x704"}, + {39, "Power PC 750", "Power PC 750"}, + {40, "Intel(R) Core(TM) Duo processor", "Core Duo"}, + {41, "Intel(R) Core(TM) Duo mobile processor", "Core Duo Mobile"}, + {42, "Intel(R) Core(TM) Solo mobile processor", "Core Solo Mobile"}, + {43, "Intel(R) Atom(TM) processor", "Atom"}, + + {48, "Alpha Family", "Alpha"}, + {49, "Alpha 21064", "Alpha 21064"}, + {50, "Alpha 21066", "Alpha 21066"}, + {51, "Alpha 21164", "Alpha 21164"}, + {52, "Alpha 21164PC", "Alpha 21164PC"}, + {53, "Alpha 21164a", "Alpha 21164a"}, + {54, "Alpha 21264", "Alpha 21264"}, + {55, "Alpha 21364", "Alpha 21364"}, + {56, "AMD Turion(TM) II Ultra Dual-Core Mobile M Processor Family", + "Turion II Ultra Dual-Core Mobile M"}, + {57, "AMD Turion(TM) II Dual-Core Mobile M Processor Family", + "Turion II Dual-Core Mobile M"}, + {58, "AMD Athlon(TM) II Dual-Core Mobile M Processor Family", + "Athlon II Dual-Core M"}, + {59, "AMD Opteron(TM) 6100 Series Processor", "Opteron 6100"}, + {60, "AMD Opteron(TM) 4100 Series Processor", "Opteron 4100"}, + {61, "AMD Opteron(TM) 6200 Series Processor", "Opteron 6200"}, + {62, "AMD Opteron(TM) 4200 Series Processor", "Opteron 4200"}, + + /* + {63, "AMD FX(TM) Series Processor", ""}, + */ + {64, "MIPS Family", "MIPS"}, + {65, "MIPS R4000", "MIPS R4000"}, + {66, "MIPS R4200", "MIPS R4200"}, + {67, "MIPS R4400", "MIPS R4400"}, + {68, "MIPS R4600", "MIPS R4600"}, + {69, "MIPS R10000", "MIPS R10000"}, + {70, "AMD C-Series Processor", "C-Series"}, + {71, "AMD E-Series Processor", "E-Series"}, + /* + {72, "AMD A-Series Processor", ""}, + */ + {73, "AMD G-Series Processor", "G-Series"}, + /* + {74, "AMD Z-Series Processor", ""}, + {75, "AMD R-Series Processor", ""}, + {76, "AMD Opteron(TM) 4300 Series Processor", ""}, + {77, "AMD Opteron(TM) 6300 Series Processor", ""}, + {78, "AMD Opteron(TM) 3300 Series Processor", ""}, + {79, "AMD FirePro(TM) Series Processor", ""}, + */ + + {80, "SPARC Family", "SPARC"}, + {81, "SuperSPARC", "SuperSPARC"}, + {82, "microSPARC II", "MicroSPARC II"}, + {83, "microSPARC IIep", "MicroSPARC IIep"}, + {84, "UltraSPARC", "UltraSPARC"}, + {85, "UltraSPARC II", "UltraSPARC II"}, + {86, "UltraSPARC IIi", "UltraSPARC IIi"}, + {87, "UltraSPARC III", "UltraSPARC III"}, + {88, "UltraSPARC IIIi", "UltraSPARC IIIi"}, + + {96, "68040", "68040"}, + {97, "68xxx Family", "68xxx"}, + {98, "68000", "68000"}, + {99, "68010", "68010"}, + {100, "68020", "68020"}, + {101, "68030", "68030"}, + + {112, "Hobbit Family", "Hobbit"}, + + {120, "Crusoe(TM) TM5000 Family", "Crusoe TM5000"}, + {121, "Crusoe(TM) TM3000 Family", "Crusoe TM3000"}, + {122, "Efficeon(TM) TM8000 Family", "Efficeon TM8000"}, + + {128, "Weitek", "Weitek"}, + + {130, "Itanium(TM) Processor", "Itanium"}, + {131, "AMD Athlon(TM) 64 Processor Family", "Athlon 64"}, + {132, "AMD Opteron(TM) Processor Family", "Opteron"}, + {133, "AMD Sempron(TM) Processor Family", "Sempron"}, + {134, "AMD Turion(TM) 64 Mobile Technology", "Turion 64"}, + {135, "Dual-Core AMD Opteron(TM) Processor Family", + "Dual-Core Opteron"}, + {136, "AMD Athlon(TM) 64 X2 Dual-Core Processor Family", + "Athlon 64 X2"}, + {137, "AMD Turion(TM) 64 X2 Mobile Technology", "Turion 64 X2"}, + {138, "Quad-Core AMD Opteron(TM) Processor Family", + "Quad-Core Opteron"}, + {139, "Third-Generation AMD Opteron(TM) Processor Family", + "Third-Generation Opteron"}, + {140, "AMD Phenom(TM) FX Quad-Core Processor Family", "Phenom FX"}, + {141, "AMD Phenom(TM) X4 Quad-Core Processor Family", "Phenom X4"}, + {142, "AMD Phenom(TM) X2 Dual-Core Processor Family", "Phenom X2"}, + {143, "AMD Athlon(TM) X2 Dual-Core Processor Family", "Athlon X2"}, + {144, "PA-RISC Family", "PA-RISC"}, + {145, "PA-RISC 8500", "PA-RISC 8500"}, + {146, "PA-RISC 8000", "PA-RISC 8000"}, + {147, "PA-RISC 7300LC", "PA-RISC 7300LC"}, + {148, "PA-RISC 7200", "PA-RISC 7200"}, + {149, "PA-RISC 7100LC", "PA-RISC 7100LC"}, + {150, "PA-RISC 7100", "PA-RISC 7100"}, + + {161, "Quad-Core Intel(R) Xeon(R) processor 3200 Series", + "Quad-Core Xeon 3200"}, + {162, "Dual-Core Intel(R) Xeon(R) processor 3000 Series", + "Dual-Core Xeon 3000"}, + {163, "Quad-Core Intel(R) Xeon(R) processor 5300 Series", + "Quad-Core Xeon 5300"}, + {164, "Dual-Core Intel(R) Xeon(R) processor 5100 Series", + "Dual-Core Xeon 5100"}, + {165, "Dual-Core Intel(R) Xeon(R) processor 5000 Series", + "Dual-Core Xeon 5000"}, + {166, "Dual-Core Intel(R) Xeon(R) processor LV", "Dual-Core Xeon LV"}, + {167, "Dual-Core Intel(R) Xeon(R) processor ULV", + "Dual-Core Xeon ULV"}, + {168, "Dual-Core Intel(R) Xeon(R) processor 7100 Series", + "Dual-Core Xeon 7100"}, + {169, "Quad-Core Intel(R) Xeon(R) processor 5400 Series", + "Quad-Core Xeon 5400"}, + {170, "Quad-Core Intel(R) Xeon(R) processor", "Quad-Core Xeon"}, + {171, "Dual-Core Intel(R) Xeon(R) processor 5200 Series", + "Dual-Core Xeon 5200"}, + {172, "Dual-Core Intel(R) Xeon(R) processor 7200 Series", + "Dual-Core Xeon 7200"}, + {173, "Quad-Core Intel(R) Xeon(R) processor 7300 Series", + "Quad-Core Xeon 7300"}, + {174, "Quad-Core Intel(R) Xeon(R) processor 7400 Series", + "Quad-Core Xeon 7400"}, + {175, "Multi-Core Intel(R) Xeon(R) processor 7400 Series", + "Multi-Core Xeon 7400"}, + {176, "Pentium(R) III Xeon(TM)", "Pentium III Xeon"}, + {177, "Pentium(R) III Processor with Intel(R) SpeedStep(TM) Technology", + "Pentium III Speedstep"}, + {178, "Pentium(R) 4", "Pentium 4"}, + {179, "Intel(R) Xeon(TM)", "Xeon"}, + {180, "AS400 Family", "AS400"}, + {181, "Intel(R) Xeon(TM) processor MP", "Xeon MP"}, + {182, "AMD Athlon(TM) XP Family", "Athlon XP"}, + {183, "AMD Athlon(TM) MP Family", "Athlon MP"}, + {184, "Intel(R) Itanium(R) 2", "Itanium 2"}, + {185, "Intel(R) Pentium(R) M processor", "Pentium M"}, + {186, "Intel(R) Celeron(R) D processor", "Celeron D"}, + {187, "Intel(R) Pentium(R) D processor", "Pentium D"}, + {188, "Intel(R) Pentium(R) Processor Extreme Edition", "Pentium EE"}, + {189, "Intel(R) Core(TM) Solo Processor", "Core Solo"}, + {190, "K7", "K7"}, + {191, "Intel(R) Core(TM)2 Duo Processor", "Core 2 Duo"}, + {192, "Intel(R) Core(TM)2 Solo processor", "Core 2 Solo"}, + {193, "Intel(R) Core(TM)2 Extreme processor", "Core 2 Extreme"}, + {194, "Intel(R) Core(TM)2 Quad processor", "Core 2 Quad"}, + {195, "Intel(R) Core(TM)2 Extreme mobile processor", + "Core 2 Extreme Mobile"}, + {196, "Intel(R) Core(TM)2 Duo mobile processor", "Core 2 Duo Mobile"}, + {197, "Intel(R) Core(TM)2 Solo mobile processor", + "Core 2 Solo Mobile"}, + {198, "Intel(R) Core(TM) i7 processor", "Core i7"}, + {199, "Dual-Core Intel(R) Celeron(R) Processor", "Dual-Core Celeron"}, + {200, "S/390 and zSeries Family", "IBM390"}, + {201, "ESA/390 G4", "G4"}, + {202, "ESA/390 G5", "G5"}, + {203, "ESA/390 G6", "ESA/390 G6"}, + {204, "z/Architectur base", "z/Architectur"}, /* this is not typo */ + {205, "Intel(R) Core(TM) i5 processor", "Core i5"}, + {206, "Intel(R) Core(TM) i3 processor", "Core i3"}, + + {210, "VIA C7(TM)-M Processor Family", "C7-M"}, + {211, "VIA C7(TM)-D Processor Family", "C7-D"}, + {212, "VIA C7(TM) Processor Family", "C7"}, + {213, "VIA Eden(TM) Processor Family", "Eden"}, + {214, "Multi-Core Intel(R) Xeon(R) processor", "Multi-Core Xeon"}, + {215, "Dual-Core Intel(R) Xeon(R) processor 3xxx Series", + "Dual-Core Xeon 3xxx"}, + {216, "Quad-Core Intel(R) Xeon(R) processor 3xxx Series", + "Quad-Core Xeon 3xxx"}, + {217, "VIA Nano(TM) Processor Family", "Nano"}, + {218, "Dual-Core Intel(R) Xeon(R) processor 5xxx Series", + "Dual-Core Xeon 5xxx"}, + {219, "Quad-Core Intel(R) Xeon(R) processor 5xxx Series", + "Quad-Core Xeon 5xxx"}, + + {221, "Dual-Core Intel(R) Xeon(R) processor 7xxx Series", + "Dual-Core Xeon 7xxx"}, + {222, "Quad-Core Intel(R) Xeon(R) processor 7xxx Series", + "Quad-Core Xeon 7xxx"}, + {223, "Multi-Core Intel(R) Xeon(R) processor 7xxx Series", + "Multi-Core Xeon 7xxx"}, + {224, "Multi-Core Intel(R) Xeon(R) processor 3400 Series", + "Multi-Core Xeon 3400"}, + + /* + {228, "AMD Opteron(TM) 3000 Series Processor", ""}, + {229, "AMD Sempron(TM) II Processor Family", ""}, + */ + {230, "Embedded AMD Opteron(TM) Quad-Core Processor Family", + "Embedded Opteron Quad-Core"}, + {231, "AMD Phenom(TM) Triple-Core Processor Family", + "Phenom Triple-Core"}, + {232, "AMD Turion(TM) Ultra Dual-Core Mobile Processor Family", + "Turion Ultra Dual-Core Mobile"}, + {233, "AMD Turion(TM) Dual-Core Mobile Processor Family", + "Turion Dual-Core Mobile"}, + {234, "AMD Athlon(TM) Dual-Core Processor Family", "Athlon Dual-Core"}, + {235, "AMD Sempron(TM) SI Processor Family", "Sempron SI"}, + {236, "AMD Phenom(TM) II Processor Family", "Phenom II"}, + {237, "AMD Athlon(TM) II Processor Family", "Athlon II"}, + {238, "Six-Core AMD Opteron(TM) Processor Family", "Six-Core Opteron"}, + {239, "AMD Sempron(TM) M Processor Family", "Sempron M"}, + + {250, "i860", "i860"}, + {251, "i960", "i960"}, + + {260, "SH-3", "SH-3"}, + {261, "SH-4", "SH-4"}, + {280, "ARM", "ARM"}, + {281, "StrongARM", "StrongARM"}, + {300, "6x86", "6x86"}, + {301, "MediaGX", "MediaGX"}, + {302, "MII", "MII"}, + {320, "WinChip", "WinChip"}, + {350, "DSP", "DSP"}, + {500, "Video Processor", "Video Processor"}, + + /* + {254, "Reserved (SMBIOS Extension)", ""}, + {255, "Reserved (Un-initialized Flash Content - Lo)", ""}, + + {65534, "Reserved (For Future Special Purpose Assignment)", ""}, + {65535, "Reserved (Un-initialized Flash Content - Hi)", ""}, + */ + }; + + size_t i, fm_length = sizeof(fm) / sizeof(fm[0]); + + for (i = 0; i < fm_length; i++) { + if (strcmp(dmi_family, fm[i].search) == 0) { + return fm[i].value_map; + } + } + + return 1; /* Other */ +} + +KONKRET_REGISTRATION( + "root/cimv2", + "LMI_Processor", + "LMI_Processor", + "instance method") diff --git a/src/hardware/cpuinfo.c b/src/hardware/cpuinfo.c new file mode 100644 index 0000000..d80e1cb --- /dev/null +++ b/src/hardware/cpuinfo.c @@ -0,0 +1,145 @@ +/* + * 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 + */ + +#include "cpuinfo.h" + + +/* + * Initialize CpuinfoProcessor attributes. + * @param cpu + */ +void init_cpuinfoprocessor_struct(CpuinfoProcessor *cpu) +{ + cpu->flags_nb = 0; + cpu->flags = NULL; + cpu->address_size = 0; + cpu->model_name = NULL; +} + +/* + * Check attributes of cpu structure and fill in defaults if needed. + * @param cpu + * @return 0 if success, negative value otherwise + */ +short check_cpuinfoprocessor_attributes(CpuinfoProcessor *cpu) +{ + short ret = -1; + + if (!cpu->model_name) { + if (!(cpu->model_name = strdup(""))) { + ret = -2; + goto done; + } + } + + ret = 0; + +done: + if (ret != 0) { + warn("Failed to allocate memory."); + } + + return ret; +} + +short cpuinfo_get_processor(CpuinfoProcessor *cpu) +{ + short ret = -1; + unsigned i, buffer_size = 0; + char **buffer = NULL, *buf; + + /* read /proc/cpuinfo file */ + if (read_file("/proc/cpuinfo", &buffer, &buffer_size) != 0) { + ret = -2; + goto done; + } + + init_cpuinfoprocessor_struct(cpu); + + /* parse information about processor */ + for (i = 0; i < buffer_size; i++) { + /* CPU Flags */ + buf = copy_string_part_after_delim(buffer[i], "flags\t\t: "); + if (buf) { + if (explode(buf, NULL, &cpu->flags, &cpu->flags_nb) != 0) { + ret = -3; + goto done; + } + free(buf); + buf = NULL; + continue; + } + /* Address Size */ + buf = copy_string_part_after_delim(buffer[i], " bits physical, "); + if (buf) { + sscanf(buf, "%u", &cpu->address_size); + free(buf); + buf = NULL; + continue; + } + /* Model Name */ + buf = copy_string_part_after_delim(buffer[i], "model name\t: "); + if (buf) { + cpu->model_name = buf; + buf = NULL; + continue; + } + } + + if (check_cpuinfoprocessor_attributes(cpu) != 0) { + ret = -4; + goto done; + } + + ret = 0; + +done: + free_2d_buffer(&buffer, &buffer_size); + + if (ret != 0) { + cpuinfo_free_processor(cpu); + } + + return ret; +} + +void cpuinfo_free_processor(CpuinfoProcessor *cpu) +{ + if (cpu) { + if (cpu->flags_nb > 0) { + unsigned i; + for (i = 0; i < cpu->flags_nb; i++) { + if (cpu->flags[i]) { + free(cpu->flags[i]); + } + cpu->flags[i] = NULL; + } + free(cpu->flags); + } + cpu->flags_nb = 0; + cpu->flags = NULL; + if (cpu->model_name) { + free(cpu->model_name); + } + cpu->model_name = NULL; + } + + return; +} diff --git a/src/hardware/cpuinfo.h b/src/hardware/cpuinfo.h new file mode 100644 index 0000000..5ec5dd5 --- /dev/null +++ b/src/hardware/cpuinfo.h @@ -0,0 +1,54 @@ +/* + * 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 + */ + +#ifndef CPUINFO_H_ +#define CPUINFO_H_ + +#include +#include +#include +#include "globals.h" +#include "utils.h" + + +/* Processor from /proc/cpuinfo file. */ +typedef struct _CpuinfoProcessor { + unsigned flags_nb; /* Number of CPU Flags */ + char **flags; /* CPU Flags */ + unsigned address_size; /* Address Size / Address Width */ + char *model_name; /* Model Name */ +} CpuinfoProcessor; + + +/* + * Get processor structure according to the /proc/cpuinfo file. + * @param cpu + * @return 0 if success, negative value otherwise + */ +short cpuinfo_get_processor(CpuinfoProcessor *cpu); + +/* + * Free attributes in the cpuinfo structure. + * @param cpu structure + */ +void cpuinfo_free_processor(CpuinfoProcessor *cpu); + + +#endif /* CPUINFO_H_ */ diff --git a/src/hardware/dmidecode.c b/src/hardware/dmidecode.c new file mode 100644 index 0000000..6a038fb --- /dev/null +++ b/src/hardware/dmidecode.c @@ -0,0 +1,343 @@ +/* + * 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 + */ + +#include "dmidecode.h" + + +/* + * Initialize DmiProcessor attributes. + * @param cpu + */ +void init_dmiprocessor_struct(DmiProcessor *cpu) +{ + cpu->id = NULL; + cpu->family = NULL; + cpu->status = NULL; + cpu->current_speed = 0; + cpu->max_speed = 0; + cpu->external_clock = 0; + cpu->name = NULL; + cpu->enabled_cores = 1; + cpu->type = NULL; + cpu->stepping = NULL; + cpu->upgrade = NULL; + cpu->charact_nb = 0; + cpu->characteristics = NULL; +} + +/* + * Check attributes of cpu structure and fill in defaults if needed. + * @param cpu + * @return 0 if success, negative value otherwise + */ +short check_dmiprocessor_attributes(DmiProcessor *cpu) +{ + short ret = -1; + + if (!cpu->id) { + if (!(cpu->id = strdup(""))) { + ret = -2; + goto done; + } + } + if (!cpu->family) { + if (!(cpu->family = strdup("Unknown"))) { + ret = -3; + goto done; + } + } + if (!cpu->status) { + if (!(cpu->status = strdup("Unknown"))) { + ret = -4; + goto done; + } + } + if (!cpu->name) { + if (!(cpu->name = strdup(""))) { + ret = -5; + goto done; + } + } + if (!cpu->type) { + if (!(cpu->type = strdup(""))) { + ret = -6; + goto done; + } + } + if (!cpu->stepping) { + if (!(cpu->stepping = strdup(""))) { + ret = -7; + goto done; + } + } + if (!cpu->upgrade) { + if (!(cpu->upgrade = strdup("Unknown"))) { + ret = -8; + goto done; + } + } + + ret = 0; + +done: + if (ret != 0) { + warn("Failed to allocate memory."); + } + + return ret; +} + +short dmi_get_processors(DmiProcessor **cpus, unsigned *cpus_nb) +{ + short ret = -1; + int curr_cpu = -1; + unsigned i, buffer_size = 0; + char **buffer = NULL, *buf; + + *cpus_nb = 0; + + /* get dmidecode output */ + if (run_command("dmidecode -t 4", &buffer, &buffer_size) != 0) { + ret = -2; + goto done; + } + + /* count processors */ + for (i = 0; i < buffer_size; i++) { + if (strncmp(buffer[i], "Handle 0x", 9) == 0) { + (*cpus_nb)++; + } + } + + /* if no processor was found */ + if (*cpus_nb < 1) { + warn("Dmidecode didn't recognize any processor."); + ret = -3; + goto done; + } + + /* allocate memory for processors */ + *cpus = (DmiProcessor *)calloc(*cpus_nb, sizeof(DmiProcessor)); + if (!(*cpus)) { + warn("Failed to allocate memory."); + ret = -4; + goto done; + } + + /* parse information about processors */ + for (i = 0; i < buffer_size; i++) { + if (strncmp(buffer[i], "Handle 0x", 9) == 0) { + curr_cpu++; + init_dmiprocessor_struct(cpus[curr_cpu]); + continue; + } + /* ignore first useless lines */ + if (curr_cpu < 0) { + continue; + } + /* ID */ + buf = copy_string_part_after_delim(buffer[i], "ID: "); + if (buf) { + cpus[curr_cpu]->id = buf; + buf = NULL; + continue; + } + /* Family */ + buf = copy_string_part_after_delim(buffer[i], "Family: "); + if (buf) { + cpus[curr_cpu]->family = buf; + buf = NULL; + continue; + } + /* Status */ + buf = copy_string_part_after_delim(buffer[i], "Status: Populated, "); + if (buf) { + cpus[curr_cpu]->status = buf; + buf = NULL; + continue; + } + /* Current Speed */ + buf = copy_string_part_after_delim(buffer[i], "Current Speed: "); + if (buf && strcmp(buf, "Unknown") != 0) { + sscanf(buf, "%u", &cpus[curr_cpu]->current_speed); + free(buf); + buf = NULL; + continue; + } + /* Max Speed */ + buf = copy_string_part_after_delim(buffer[i], "Max Speed: "); + if (buf && strcmp(buf, "Unknown") != 0) { + sscanf(buf, "%u", &cpus[curr_cpu]->max_speed); + free(buf); + buf = NULL; + continue; + } + /* External Clock Speed */ + buf = copy_string_part_after_delim(buffer[i], "External Clock: "); + if (buf && strcmp(buf, "Unknown") != 0) { + sscanf(buf, "%u", &cpus[curr_cpu]->external_clock); + free(buf); + buf = NULL; + continue; + } + /* CPU Name */ + buf = copy_string_part_after_delim(buffer[i], "Version: "); + if (buf) { + cpus[curr_cpu]->name = buf; + buf = NULL; + continue; + } + /* Enabled Cores */ + buf = copy_string_part_after_delim(buffer[i], "Core Enabled: "); + if (buf) { + sscanf(buf, "%u", &cpus[curr_cpu]->enabled_cores); + free(buf); + buf = NULL; + continue; + } + /* CPU Type/Role */ + buf = copy_string_part_after_delim(buffer[i], "Type: "); + if (buf) { + cpus[curr_cpu]->type = buf; + buf = NULL; + continue; + } + /* Stepping */ + buf = copy_string_part_after_delim(buffer[i], ", Stepping "); + if (buf) { + cpus[curr_cpu]->stepping = buf; + buf = NULL; + continue; + } + /* Upgrade */ + buf = copy_string_part_after_delim(buffer[i], "Upgrade: "); + if (buf) { + cpus[curr_cpu]->upgrade = buf; + buf = NULL; + continue; + } + /* CPU Characteristics */ + if (strstr(buffer[i], "Characteristics:") + && !strstr(buffer[i], "Characteristics: ")) { + /* count characteristics */ + cpus[curr_cpu]->charact_nb = 0; + while (strlen(buffer[i + cpus[curr_cpu]->charact_nb + 1])) { + cpus[curr_cpu]->charact_nb += 1; + } + /* allocate memory */ + cpus[curr_cpu]->characteristics = + (char **)calloc(cpus[curr_cpu]->charact_nb, sizeof(char *)); + if (!cpus[curr_cpu]->characteristics) { + warn("Failed to allocate memory."); + ret = -5; + goto done; + } + unsigned j; + char *tmp_line; + for (j = 0; j < cpus[curr_cpu]->charact_nb; j++) { + tmp_line = trim(buffer[i + j + 1], NULL); + if (tmp_line) { + cpus[curr_cpu]->characteristics[j] = tmp_line; + } else { + cpus[curr_cpu]->characteristics[j] = strdup(""); + if (!cpus[curr_cpu]->characteristics[j]) { + warn("Failed to allocate memory."); + ret = -6; + goto done; + } + } + } + /* skip characteristics and newline after them */ + i += cpus[curr_cpu]->charact_nb + 1; + } + } + + /* fill in default attributes if needed */ + for (i = 0; i < *cpus_nb; i++) { + if (check_dmiprocessor_attributes(cpus[i]) != 0) { + ret = -7; + goto done; + } + } + + ret = 0; + +done: + free_2d_buffer(&buffer, &buffer_size); + + if (ret != 0) { + dmi_free_processors(cpus, cpus_nb); + } + + return ret; +} + +void dmi_free_processors(DmiProcessor **cpus, unsigned *cpus_nb) +{ + unsigned i, j; + + if (*cpus_nb > 0) { + for (i = 0; i < *cpus_nb; i++) { + if (cpus[i]->id) { + free(cpus[i]->id); + } + cpus[i]->id = NULL; + if (cpus[i]->family) { + free(cpus[i]->family); + } + cpus[i]->family = NULL; + if (cpus[i]->status) { + free(cpus[i]->status); + } + cpus[i]->status = NULL; + if (cpus[i]->name) { + free(cpus[i]->name); + } + cpus[i]->name = NULL; + if (cpus[i]->type) { + free(cpus[i]->type); + } + cpus[i]->type = NULL; + if (cpus[i]->stepping) { + free(cpus[i]->stepping); + } + cpus[i]->stepping = NULL; + if (cpus[i]->upgrade) { + free(cpus[i]->upgrade); + } + cpus[i]->upgrade = NULL; + if (cpus[i]->charact_nb > 0) { + for (j = 0; j < cpus[i]->charact_nb; j++) { + if (cpus[i]->characteristics[j]) { + free(cpus[i]->characteristics[j]); + } + cpus[i]->characteristics[j] = NULL; + } + free(cpus[i]->characteristics); + } + cpus[i]->charact_nb = 0; + cpus[i]->characteristics = NULL; + } + free (*cpus); + } + + *cpus_nb = 0; + *cpus = NULL; +} diff --git a/src/hardware/dmidecode.h b/src/hardware/dmidecode.h new file mode 100644 index 0000000..f7e76a9 --- /dev/null +++ b/src/hardware/dmidecode.h @@ -0,0 +1,66 @@ +/* + * 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 + */ + +#ifndef DMIDECODE_H_ +#define DMIDECODE_H_ + +#include +#include +#include +#include "globals.h" +#include "utils.h" + + +/* Processor from dmidecode. */ +typedef struct _DmiProcessor { + char *id; /* ID */ + char *family; /* Family */ + char *status; /* CPU Status */ + unsigned current_speed; /* Current Speed in MHz */ + unsigned max_speed; /* Max Speed in MHz */ + unsigned external_clock; /* External Clock Speed in MHz */ + char *name; /* CPU name, version in dmidecode */ + unsigned enabled_cores; /* Number of enabled cores */ + char *type; /* CPU Type/Role */ + char *stepping; /* Stepping (revision level within family) */ + char *upgrade; /* CPU upgrade method - socket */ + unsigned charact_nb; /* Number of CPU Characteristics */ + char **characteristics; /* CPU Characteristics */ +} DmiProcessor; + + +/* + * Get array of processors according to the dmidecode program. + * @param cpu array of cpus, this function will allocate necessary memory, + * but caller is responsible for freeing it + * @param cpus_nb number of processors in cpus + * @return 0 if success, negative value otherwise + */ +short dmi_get_processors(DmiProcessor **cpus, unsigned *cpus_nb); + +/* + * Free array of processor structures. + * @param cpus array of cpus + * @param cpus_nb number of cpus + */ +void dmi_free_processors(DmiProcessor **cpus, unsigned *cpus_nb); + + +#endif /* DMIDECODE_H_ */ diff --git a/src/hardware/lscpu.c b/src/hardware/lscpu.c new file mode 100644 index 0000000..124ed7b --- /dev/null +++ b/src/hardware/lscpu.c @@ -0,0 +1,151 @@ +/* + * 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 + */ + +#include "lscpu.h" + + +/* + * Initialize LscpuProcessor attributes. + * @param cpu + */ +void init_lscpuprocessor_struct(LscpuProcessor *cpu) +{ + cpu->data_width = 0; + cpu->processors = 0; + cpu->cores = 0; + cpu->stepping = NULL; + cpu->current_speed = 0; +} + +/* + * Check attributes of cpu structure and fill in defaults if needed. + * @param cpu + * @return 0 if success, negative value otherwise + */ +short check_lscpuprocessor_attributes(LscpuProcessor *cpu) +{ + short ret = -1; + + if (!cpu->stepping) { + if (!(cpu->stepping = strdup(""))) { + ret = -2; + goto done; + } + } + + ret = 0; + +done: + if (ret != 0) { + warn("Failed to allocate memory."); + } + + return ret; +} + +short lscpu_get_processor(LscpuProcessor *cpu) +{ + short ret = -1; + unsigned i, buffer_size = 0; + char **buffer = NULL, *buf; + + /* get lscpu output */ + if (run_command("lscpu", &buffer, &buffer_size) != 0) { + ret = -2; + goto done; + } + + init_lscpuprocessor_struct(cpu); + + /* parse information about processor */ + for (i = 0; i < buffer_size; i++) { + /* Data Width */ + buf = copy_string_part_after_delim(buffer[i], "CPU op-mode(s):"); + if (buf) { + if (strstr(buf, "64")) { + cpu->data_width = 64; + } else if (strstr(buf, "32")) { + cpu->data_width = 32; + } + free(buf); + buf = NULL; + continue; + } + /* Cores per processor */ + buf = copy_string_part_after_delim(buffer[i], "Core(s) per socket:"); + if (buf) { + sscanf(buf, "%u", &cpu->cores); + free(buf); + buf = NULL; + continue; + } + /* Number of processors */ + buf = copy_string_part_after_delim(buffer[i], "Socket(s):"); + if (buf) { + sscanf(buf, "%u", &cpu->processors); + free(buf); + buf = NULL; + continue; + } + /* Stepping */ + buf = copy_string_part_after_delim(buffer[i], "Stepping:"); + if (buf) { + cpu->stepping = buf; + buf = NULL; + continue; + } + /* Current speed in MHz */ + buf = copy_string_part_after_delim(buffer[i], "CPU MHz:"); + if (buf) { + sscanf(buf, "%u", &cpu->current_speed); + free(buf); + buf = NULL; + continue; + } + } + + if (check_lscpuprocessor_attributes(cpu) != 0) { + ret = -3; + goto done; + } + + ret = 0; + +done: + free_2d_buffer(&buffer, &buffer_size); + + if (ret != 0) { + lscpu_free_processor(cpu); + } + + return ret; +} + +void lscpu_free_processor(LscpuProcessor *cpus) +{ + if (cpus) { + if (cpus->stepping) { + free(cpus->stepping); + } + cpus->stepping = NULL; + } + + return; +} diff --git a/src/hardware/lscpu.h b/src/hardware/lscpu.h new file mode 100644 index 0000000..892141e --- /dev/null +++ b/src/hardware/lscpu.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 + */ + +#ifndef LSCPU_H_ +#define LSCPU_H_ + +#include +#include +#include +#include "globals.h" +#include "utils.h" + + +/* Processor from lscpu program. */ +typedef struct _LscpuProcessor { + unsigned data_width; /* Data width */ + unsigned processors; /* Number of processors */ + unsigned cores; /* Cores per processor */ + char *stepping; /* Stepping */ + unsigned current_speed; /* Current speed in MHz */ +} LscpuProcessor; + + +/* + * Get processor structure according to the lscpu program. + * @param cpu + * @return 0 if success, negative value otherwise + */ +short lscpu_get_processor(LscpuProcessor *cpu); + +/* + * Free attributes in the lscpu structure. + * @param cpu + */ +void lscpu_free_processor(LscpuProcessor *cpu); + + +#endif /* LSCPU_H_ */ diff --git a/src/hardware/utils.c b/src/hardware/utils.c new file mode 100644 index 0000000..da7bbfa --- /dev/null +++ b/src/hardware/utils.c @@ -0,0 +1,382 @@ +/* + * 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 + */ + +#include "utils.h" + + +short read_fp_to_2d_buffer(FILE *fp, char ***buffer, unsigned *buffer_size) +{ + short ret = -1; + ssize_t read; + size_t line_len = 0; + unsigned tmp_buffer_lines, lines_read = 0; + char **tmp_buffer, *line = NULL; + + free_2d_buffer(buffer, buffer_size); + + if (!fp) { + warn("Given file pointer is NULL."); + ret = -2; + goto done; + } + + /* allocate buffer */ + tmp_buffer_lines = 128; + tmp_buffer = (char **)calloc(tmp_buffer_lines, sizeof(char *)); + if (!tmp_buffer) { + warn("Failed to allocate memory."); + ret = -3; + goto done; + } + + while ((read = getline(&line, &line_len, fp)) != -1) { + /* filter comment lines */ + if (read > 0 && line[0] == '#') { + continue; + } + + /* reallocate if needed */ + if (lines_read >= tmp_buffer_lines) { + tmp_buffer_lines *= 2; + char **newtmp = (char **)realloc(tmp_buffer, + tmp_buffer_lines * sizeof(char *)); + if (!newtmp) { + warn("Failed to allocate memory."); + ret = -4; + goto done; + } + tmp_buffer = newtmp; + } + + /* copy trimmed line to buffer */ + tmp_buffer[lines_read] = trim(line, NULL); + if (!tmp_buffer[lines_read]) { + tmp_buffer[lines_read] = strdup(""); + if (!tmp_buffer[lines_read]) { + warn("Failed to allocate memory."); + ret = -5; + goto done; + } + } + lines_read++; + } + + if (lines_read < 1) { + warn("No data read from given source."); + ret = -6; + goto done; + } + + /* reallocate buffer to free unused space */ + if (tmp_buffer_lines > lines_read) { + tmp_buffer_lines = lines_read; + char **newtmp = (char **)realloc(tmp_buffer, + tmp_buffer_lines * sizeof(char *)); + if (!newtmp) { + warn("Failed to allocate memory."); + ret = -7; + goto done; + } + tmp_buffer = newtmp; + } + + *buffer_size = tmp_buffer_lines; + *buffer = tmp_buffer; + + ret = 0; + +done: + if (line) { + free(line); + } + line = NULL; + + if (ret != 0) { + free_2d_buffer(&tmp_buffer, &tmp_buffer_lines); + } + + return ret; +} + +void free_2d_buffer(char ***buffer, unsigned *buffer_size) +{ + unsigned i, tmp_buffer_lines = *buffer_size; + char **tmp_buffer = *buffer; + + if (tmp_buffer_lines > 0) { + for (i = 0; i < tmp_buffer_lines; i++) { + if (tmp_buffer[i]) { + free(tmp_buffer[i]); + } + tmp_buffer[i] = NULL; + } + free(tmp_buffer); + } + + tmp_buffer = NULL; + *buffer_size = 0; + *buffer = NULL; +} + +short run_command(const char *command, char ***buffer, unsigned *buffer_size) +{ + FILE *fp; + short ret = -1; + + /* if command is empty */ + if (!command || strlen(command) < 1) { + warn("Given command is empty."); + ret = -2; + goto done; + } + + /* execute command */ + debug("Running command: \"%s\"", command); + fp = popen(command, "r"); + if (!fp) { + warn("Failed to run command: \"%s\"; Error: %s", + command, strerror(errno)); + ret = -3; + goto done; + } + + if (read_fp_to_2d_buffer(fp, buffer, buffer_size) != 0) { + ret = -4; + goto done; + } + + ret = 0; + +done: + if (fp) { + int ret_code = pclose(fp); + if (ret_code == -1) { + warn("Failed to run command: \"%s\"; Error: %s", + command, strerror(errno)); + if (ret == 0) { + ret = -5; + } + } else if (ret_code != 0) { + warn("Command \"%s\" exited unexpectedly.", command); + if (ret == 0) { + ret = -6; + } + } + } + + if (ret != 0) { + free_2d_buffer(buffer, buffer_size); + } + + return ret; +} + +short read_file(const char *filename, char ***buffer, unsigned *buffer_size) +{ + FILE *fp; + short ret = -1; + + /* open file */ + debug("Reading \"%s\" file.", filename); + fp = fopen(filename, "r"); + if (!fp) { + warn("Failed to open \"%s\" file.", filename); + ret = -2; + goto done; + } + + if (read_fp_to_2d_buffer(fp, buffer, buffer_size) != 0) { + ret = -3; + goto done; + } + + ret = 0; + +done: + if (fp) { + fclose(fp); + } + + if (ret != 0) { + free_2d_buffer(buffer, buffer_size); + } + + return ret; +} + +char *copy_string_part_after_delim(const char *str, const char *delim) +{ + if (!str || strlen(str) < 1 || !delim || strlen(delim) < 1) { + return NULL; + } + + char *p, *out = NULL; + size_t delim_len = strlen(delim); + + /* if str contains delim and there is something after it */ + if ((p = strstr(str, delim)) && strlen(p + delim_len) > 0) { + out = trim(p + delim_len, NULL); + } + + return out; +} + +char *trim(const char *str, const char *delims) +{ + char *out; + const char *default_delims = WHITESPACES; + size_t l; + + /* if string is empty */ + if (!str || strlen(str) < 1) { + return NULL; + } + + if (!delims) { + delims = default_delims; + } + + /* trim start of the string */ + while (strchr(delims, str[0]) && str[0] != '\0') { + str++; + } + + l = strlen(str); + + /* if string was only white spaces */ + if (l < 1) { + return NULL; + } + + /* shorten length of string if there are trailing white spaces */ + while (strchr(delims, str[l - 1]) && l != 0) { + l--; + } + + /* sanity check */ + if (l < 1) { + return NULL; + } + + /* copy string */ + out = strndup(str, l); + if (!out) { + warn("Failed to allocate memory."); + } + + return out; +} + +short explode(const char *str, const char *delims, char ***buffer, unsigned *buffer_size) +{ + size_t l; + short ret = -1; + unsigned item = 0, tmp_buffer_size; + char *default_delims = WHITESPACES, *trimmed_str = NULL, *ts, **tmp_buffer; + + free_2d_buffer(buffer, buffer_size); + + if (!str || strlen(str) < 1) { + ret = 0; + goto done; + } + + if (!delims) { + delims = default_delims; + } + + trimmed_str = trim(str, delims); + if (!trimmed_str || strlen(trimmed_str) < 1) { + ret = 0; + goto done; + } + + tmp_buffer_size = 128; + tmp_buffer = (char **)calloc(tmp_buffer_size, sizeof(char *)); + if (!tmp_buffer) { + warn("Failed to allocate memory."); + ret = -2; + goto done; + } + + ts = trimmed_str; + while (ts[0] != '\0') { + /* skip leading delimiters of substring */ + while (strchr(delims, ts[0]) && ts[0] != '\0') { + ts++; + } + /* find length of valid substring */ + l = 0; + while (!strchr(delims, ts[l]) && ts[l] != '\0') { + l++; + } + /* reallocate if needed */ + if (item >= tmp_buffer_size) { + tmp_buffer_size *= 2; + char **new_temp = (char **)realloc(tmp_buffer, + tmp_buffer_size * sizeof(char *)); + if (!new_temp) { + warn("Failed to allocate memory."); + ret = -3; + goto done; + } + tmp_buffer = new_temp; + } + /* copy the substring */ + tmp_buffer[item] = strndup(ts, l); + if (!tmp_buffer[item]) { + warn("Failed to allocate memory."); + ret = -4; + goto done; + } + item++; + ts += l; + } + + /* reallocate to save unused space */ + if (tmp_buffer_size > item) { + tmp_buffer_size = item; + char **new_temp = (char **)realloc(tmp_buffer, + tmp_buffer_size * sizeof(char *)); + if (!new_temp) { + warn("Failed to allocate memory."); + ret = -5; + goto done; + } + tmp_buffer = new_temp; + } + + *buffer_size = tmp_buffer_size; + *buffer = tmp_buffer; + + ret = 0; + +done: + if (trimmed_str) { + free(trimmed_str); + } + trimmed_str = NULL; + + if (ret != 0) { + free_2d_buffer(&tmp_buffer, &tmp_buffer_size); + } + + return ret; +} diff --git a/src/hardware/utils.h b/src/hardware/utils.h new file mode 100644 index 0000000..9f5686f --- /dev/null +++ b/src/hardware/utils.h @@ -0,0 +1,111 @@ +/* + * 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 + */ + +#ifndef UTILS_H_ +#define UTILS_H_ + +#include +#include +#include +#include +#include "globals.h" + +#define WHITESPACES " \f\n\r\t\v" + + +/* + * Read given file pointer and save it's output in buffer. Number of lines read + * is stored in buffer_size. Function skips lines starting with '#'. + * Every line from output is trimmed. + * Buffer has to be NULL, and buffer_size 0. Function will allocate + * necessary memory, buffer can be freed with free_2d_buffer() function. + * @param fp file pointer to be read + * @param buffer which will be filled in + * @param buffer_size number of lines in buffer + * @return 0 if success, negative value otherwise + */ +short read_fp_to_2d_buffer(FILE *fp, char ***buffer, unsigned *buffer_size); + +/* + * Free 2D buffer. + * @param buffer + * @param buffer_size number of lines in buffer + */ +void free_2d_buffer(char ***buffer, unsigned *buffer_size); + +/* + * Run given command and store its output in buffer. Number of lines in buffer + * is stored in buffer_size. Function skips lines starting with '#'. + * Buffer has to be NULL, and buffer_size 0. Function will allocate necessary + * memory, buffer can be freed with free_2d_buffer() function. + * @param command to be run + * @param buffer + * @param buffer_size number of lines in buffer + * @return 0 if success, negative value otherwise + */ +short run_command(const char *command, char ***buffer, unsigned *buffer_size); + +/* + * Run given file and store its output in buffer. Number of lines in buffer + * is stored in buffer_size. Function skips lines starting with '#'. + * Buffer has to be NULL, and buffer_size 0. Function will allocate necessary + * memory, buffer can be freed with free_2d_buffer() function. + * @param filename + * @param buffer + * @param buffer_size number of lines in buffer + * @return 0 if success, negative value otherwise + */ +short read_file(const char *filename, char ***buffer, unsigned *buffer_size); + +/* + * Copy trimmed part of the given string after delimiter and returns pointer + * to the newly created string, allocated with malloc. + * If delimiter is not part of the string, or the string ends right after + * delimiter, NULL is returned. + * @param str string to be searched + * @param delim delimiter + * @return newly created string or NULL + */ +char *copy_string_part_after_delim(const char *str, const char *delim); + +/* + * Create trimmed copy of given string. Trimmed will be any characters + * found in delims parameter, or, if delims is NULL, any white space characters. + * @param str + * @param delims string containing delimiters. If NULL, white space characters + * are used. + * @return trimmed string allocated with malloc or NULL if allocation failed + * or given string was empty or contained only delimiters + */ +char *trim(const char *str, const char *delims); + +/* + * Explode given string to substrings delimited by delims. + * @param str input string + * @param delims string consisted of delimiters + * @param buffer output 2D buffer. Can be NULL if input string is NULL, empty, + * or only delimiters. + * @param buffer_size number of substrings + * @return 0 if success, negative value otherwise. + */ +short explode(const char *str, const char *delims, char ***buffer, unsigned *buffer_size); + + +#endif /* UTILS_H_ */ -- cgit