/* * 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; }