diff options
Diffstat (limited to 'dmi.c')
-rw-r--r-- | dmi.c | 168 |
1 files changed, 168 insertions, 0 deletions
@@ -0,0 +1,168 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2009,2010 Michael Karcher + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +#include "flash.h" + +enum dmi_strings { + DMI_SYS_MANUFACTURER, + DMI_SYS_PRODUCT, + DMI_SYS_VERSION, + DMI_BB_MANUFACTURER, + DMI_BB_PRODUCT, + DMI_BB_VERSION, + DMI_ID_INVALID /* This must always be the last entry */ +}; + +/* The short_id for baseboard starts with "m" as in mainboard to leave + "b" available for BIOS */ +struct { + const char *dmidecode_name; + char short_id[3]; +} dmi_properties[DMI_ID_INVALID] = { + {"system-manufacturer", "sm"}, + {"system-product-name", "sp"}, + {"system-version", "sv"}, + {"baseboard-manufacturer", "mm"}, + {"baseboard-product-name", "mp"}, + {"baseboard-version", "mv"} +}; + +#define DMI_COMMAND_LEN_MAX 260 +const char *dmidecode_command = "dmidecode"; + +int has_dmi_support = 0; +char *dmistrings[DMI_ID_INVALID]; + +/* strings longer than 4096 in DMI are just insane */ +#define DMI_MAX_ANSWER_LEN 4096 + +void dmi_init(void) +{ + FILE *dmidecode_pipe; + int i; + char *answerbuf = malloc(DMI_MAX_ANSWER_LEN); + if(!answerbuf) + { + fprintf(stderr, "DMI: couldn't alloc answer buffer\n"); + return; + } + for (i = 0; i < DMI_ID_INVALID; i++) + { + char commandline[DMI_COMMAND_LEN_MAX+40]; + snprintf(commandline, sizeof(commandline), + "%s -s %s", dmidecode_command, + dmi_properties[i].dmidecode_name); + dmidecode_pipe = popen(commandline, "r"); + if (!dmidecode_pipe) + { + printf_debug("DMI pipe open error\n"); + goto out_free; + } + fgets(answerbuf, DMI_MAX_ANSWER_LEN, dmidecode_pipe); + if (ferror(dmidecode_pipe)) + { + printf_debug("DMI pipe read error\n"); + pclose(dmidecode_pipe); + goto out_free; + } + /* Toss all output above DMI_MAX_ANSWER_LEN away to prevent + deadlock on pclose. */ + while (!feof(dmidecode_pipe)) + getc(dmidecode_pipe); + if (pclose(dmidecode_pipe) != 0) + { + printf_debug("DMI pipe close error\n"); + goto out_free; + } + + /* chomp trailing newline */ + if (answerbuf[0] != 0 && + answerbuf[strlen(answerbuf) - 1] == '\n') + answerbuf[strlen(answerbuf) - 1] = 0; + printf_debug("DMI string %d: \"%s\"\n", i, answerbuf); + dmistrings[i] = strdup(answerbuf); + } + has_dmi_support = 1; +out_free: + free(answerbuf); +} + +/** + * Does an substring/prefix/postfix/whole-string match. + * + * The pattern is matched as-is. The only metacharacters supported are '^' + * at the beginning and '$' at the end. So you can look for "^prefix", + * "suffix$", "substring" or "^complete string$". + * + * @param value The string to check. + * @param pattern The pattern. + * @return Nonzero if pattern matches. + */ +static int dmi_compare(const char *value, const char *pattern) +{ + int anchored = 0; + int patternlen; + printf_debug("matching %s against %s\n", value, pattern); + /* The empty string is part of all strings */ + if (pattern[0] == 0) + return 1; + + if (pattern[0] == '^') { + anchored = 1; + pattern++; + } + + patternlen = strlen(pattern); + if (pattern[patternlen - 1] == '$') { + int valuelen = strlen(value); + patternlen--; + if(patternlen > valuelen) + return 0; + + /* full string match: require same length */ + if(anchored && (valuelen != patternlen)) + return 0; + + /* start character to make ends match */ + value += valuelen - patternlen; + anchored = 1; + } + + if (anchored) + return strncmp(value, pattern, patternlen) == 0; + else + return strstr(value, pattern) != NULL; +} + +int dmi_match(const char *pattern) +{ + int i; + if (!has_dmi_support) + return 0; + + for (i = 0;i < DMI_ID_INVALID; i++) + return dmi_compare(dmistrings[i], pattern); + + return 0; +} |