blob: bb285f400b291eccfd0d8f138566f63f44ceb68d [file] [log] [blame]
Michael Karcher6701ee82010-01-20 14:14:11 +00001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2009,2010 Michael Karcher
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include <string.h>
22#include <stdio.h>
23#include <stdlib.h>
24
25#include "flash.h"
26
27enum dmi_strings {
28 DMI_SYS_MANUFACTURER,
29 DMI_SYS_PRODUCT,
30 DMI_SYS_VERSION,
31 DMI_BB_MANUFACTURER,
32 DMI_BB_PRODUCT,
33 DMI_BB_VERSION,
Uwe Hermann43959702010-03-13 17:28:29 +000034 DMI_ID_INVALID, /* This must always be the last entry! */
Michael Karcher6701ee82010-01-20 14:14:11 +000035};
36
Uwe Hermann43959702010-03-13 17:28:29 +000037/*
38 * The short_id for baseboard starts with "m" as in mainboard to leave
39 * "b" available for BIOS.
40 */
Michael Karcherf6498d72010-02-24 22:43:44 +000041const char *dmidecode_names[DMI_ID_INVALID] = {
42 "system-manufacturer",
43 "system-product-name",
44 "system-version",
45 "baseboard-manufacturer",
46 "baseboard-product-name",
Uwe Hermann43959702010-03-13 17:28:29 +000047 "baseboard-version",
Michael Karcher6701ee82010-01-20 14:14:11 +000048};
49
50#define DMI_COMMAND_LEN_MAX 260
51const char *dmidecode_command = "dmidecode";
52
53int has_dmi_support = 0;
54char *dmistrings[DMI_ID_INVALID];
55
Uwe Hermann43959702010-03-13 17:28:29 +000056/* Strings longer than 4096 in DMI are just insane. */
Michael Karcher6701ee82010-01-20 14:14:11 +000057#define DMI_MAX_ANSWER_LEN 4096
58
Michael Karcher0d7fb7c2010-02-26 09:51:16 +000059static char *get_dmi_string(const char *string_name)
Michael Karcher6701ee82010-01-20 14:14:11 +000060{
61 FILE *dmidecode_pipe;
Michael Karcher0d7fb7c2010-02-26 09:51:16 +000062 char *result;
63 char answerbuf[DMI_MAX_ANSWER_LEN];
Uwe Hermann43959702010-03-13 17:28:29 +000064 char commandline[DMI_COMMAND_LEN_MAX + 40];
65
Michael Karcher0d7fb7c2010-02-26 09:51:16 +000066 snprintf(commandline, sizeof(commandline),
67 "%s -s %s", dmidecode_command, string_name);
68 dmidecode_pipe = popen(commandline, "r");
69 if (!dmidecode_pipe) {
70 printf_debug("DMI pipe open error\n");
71 return NULL;
Michael Karcher6701ee82010-01-20 14:14:11 +000072 }
Michael Karcher0d7fb7c2010-02-26 09:51:16 +000073 if (!fgets(answerbuf, DMI_MAX_ANSWER_LEN, dmidecode_pipe) &&
74 ferror(dmidecode_pipe)) {
75 printf_debug("DMI pipe read error\n");
76 pclose(dmidecode_pipe);
77 return NULL;
78 }
79 /* Toss all output above DMI_MAX_ANSWER_LEN away to prevent
80 deadlock on pclose. */
81 while (!feof(dmidecode_pipe))
82 getc(dmidecode_pipe);
83 if (pclose(dmidecode_pipe) != 0) {
84 printf_debug("DMI pipe close error\n");
85 return NULL;
86 }
Michael Karcher6701ee82010-01-20 14:14:11 +000087
Uwe Hermann43959702010-03-13 17:28:29 +000088 /* Chomp trailing newline. */
Michael Karcher0d7fb7c2010-02-26 09:51:16 +000089 if (answerbuf[0] != 0 &&
90 answerbuf[strlen(answerbuf) - 1] == '\n')
91 answerbuf[strlen(answerbuf) - 1] = 0;
92 printf_debug("DMI string %s: \"%s\"\n", string_name, answerbuf);
93
94 result = strdup(answerbuf);
95 if (!result)
96 puts("WARNING: Out of memory - DMI support fails");
97
98 return result;
99}
100
101void dmi_init(void)
102{
103 int i;
Michael Karcher8c1df282010-02-26 09:51:20 +0000104 char *chassis_type;
Uwe Hermann43959702010-03-13 17:28:29 +0000105
Michael Karcher6701ee82010-01-20 14:14:11 +0000106 has_dmi_support = 1;
Michael Karcher0d7fb7c2010-02-26 09:51:16 +0000107 for (i = 0; i < DMI_ID_INVALID; i++) {
108 dmistrings[i] = get_dmi_string(dmidecode_names[i]);
109 if (!dmistrings[i]) {
110 has_dmi_support = 0;
111 break;
112 }
113 }
Michael Karcher8c1df282010-02-26 09:51:20 +0000114
115 chassis_type = get_dmi_string("chassis-type");
116 if (chassis_type && !strcmp(chassis_type, "Notebook")) {
117 printf_debug("Laptop detected via DMI");
118 is_laptop = 1;
119 }
120 free(chassis_type);
Michael Karcher6701ee82010-01-20 14:14:11 +0000121}
122
123/**
124 * Does an substring/prefix/postfix/whole-string match.
125 *
126 * The pattern is matched as-is. The only metacharacters supported are '^'
127 * at the beginning and '$' at the end. So you can look for "^prefix",
128 * "suffix$", "substring" or "^complete string$".
129 *
130 * @param value The string to check.
131 * @param pattern The pattern.
132 * @return Nonzero if pattern matches.
133 */
134static int dmi_compare(const char *value, const char *pattern)
135{
136 int anchored = 0;
137 int patternlen;
Uwe Hermann43959702010-03-13 17:28:29 +0000138
Michael Karcher6701ee82010-01-20 14:14:11 +0000139 printf_debug("matching %s against %s\n", value, pattern);
Uwe Hermann43959702010-03-13 17:28:29 +0000140 /* The empty string is part of all strings! */
Michael Karcher6701ee82010-01-20 14:14:11 +0000141 if (pattern[0] == 0)
142 return 1;
143
144 if (pattern[0] == '^') {
145 anchored = 1;
146 pattern++;
147 }
148
149 patternlen = strlen(pattern);
150 if (pattern[patternlen - 1] == '$') {
151 int valuelen = strlen(value);
152 patternlen--;
Uwe Hermann43959702010-03-13 17:28:29 +0000153 if (patternlen > valuelen)
Michael Karcher6701ee82010-01-20 14:14:11 +0000154 return 0;
155
156 /* full string match: require same length */
Uwe Hermann43959702010-03-13 17:28:29 +0000157 if (anchored && (valuelen != patternlen))
Michael Karcher6701ee82010-01-20 14:14:11 +0000158 return 0;
159
160 /* start character to make ends match */
161 value += valuelen - patternlen;
162 anchored = 1;
163 }
164
165 if (anchored)
166 return strncmp(value, pattern, patternlen) == 0;
167 else
168 return strstr(value, pattern) != NULL;
169}
170
171int dmi_match(const char *pattern)
172{
173 int i;
Uwe Hermann43959702010-03-13 17:28:29 +0000174
Michael Karcher6701ee82010-01-20 14:14:11 +0000175 if (!has_dmi_support)
176 return 0;
177
Uwe Hermann43959702010-03-13 17:28:29 +0000178 for (i = 0; i < DMI_ID_INVALID; i++)
179 if (dmi_compare(dmistrings[i], pattern))
Michael Karcher4dfa0932010-02-12 05:44:18 +0000180 return 1;
Michael Karcher6701ee82010-01-20 14:14:11 +0000181
182 return 0;
183}