summaryrefslogtreecommitdiffstats
path: root/src/hardware/dmidecode.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/hardware/dmidecode.c')
-rw-r--r--src/hardware/dmidecode.c343
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;
+}