diff options
Diffstat (limited to 'src/hardware/dmidecode.c')
-rw-r--r-- | src/hardware/dmidecode.c | 343 |
1 files changed, 343 insertions, 0 deletions
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 <pschiffe@redhat.com> + */ + +#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; +} |