Flashrom

Flashrom Svn Source Tree

Root/trunk/dmi.c

1/*
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#include "programmer.h"
27
28int has_dmi_support = 0;
29
30#if STANDALONE
31
32/* Stub to indicate missing DMI functionality.
33 * has_dmi_support is 0 by default, so nothing to do here.
34 * Because dmidecode is not available on all systems, the goal is to implement
35 * the DMI subset we need directly in this file.
36 */
37void dmi_init(void)
38{
39}
40
41int dmi_match(const char *pattern)
42{
43return 0;
44}
45
46#else /* STANDALONE */
47
48static const char *dmidecode_names[] = {
49"system-manufacturer",
50"system-product-name",
51"system-version",
52"baseboard-manufacturer",
53"baseboard-product-name",
54"baseboard-version",
55};
56
57/* This list is used to identify supposed laptops. The is_laptop field has the
58 * following meaning:
59 * - 0: in all likelihood not a laptop
60 * - 1: in all likelihood a laptop
61 * - 2: chassis-type is not specific enough
62 * A full list of chassis types can be found in the System Management BIOS
63 * (SMBIOS) Reference Specification 2.7.0 section 7.4.1 "Chassis Types" at
64 * http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.0.pdf
65 * The types below are the most common ones.
66 */
67static const struct {
68unsigned char type;
69unsigned char is_laptop;
70const char *name;
71} dmi_chassis_types[] = {
72{0x01, 2, "Other"},
73{0x02, 2, "Unknown"},
74{0x03, 0, "Desktop",},
75{0x06, 0, "Mini Tower"},
76{0x07, 0, "Tower"},
77{0x08, 1, "Portable"},
78{0x09, 1, "Laptop"},
79{0x0a, 1, "Notebook"},
80{0x0b, 1, "Hand Held"},
81{0x0e, 1, "Sub Notebook"},
82{0x11, 0, "Main Server Chassis"},
83{0x17, 0, "Rack Mount Chassis"},
84{0x18, 0, "Sealed-case PC"}, /* used by Supermicro (X8SIE) */
85};
86
87#define DMI_COMMAND_LEN_MAX 260
88static const char *dmidecode_command = "dmidecode";
89
90static char *dmistrings[ARRAY_SIZE(dmidecode_names)];
91
92/* Strings longer than 4096 in DMI are just insane. */
93#define DMI_MAX_ANSWER_LEN 4096
94
95static char *get_dmi_string(const char *string_name)
96{
97FILE *dmidecode_pipe;
98char *result;
99char answerbuf[DMI_MAX_ANSWER_LEN];
100char commandline[DMI_COMMAND_LEN_MAX + 40];
101
102snprintf(commandline, sizeof(commandline),
103 "%s -s %s", dmidecode_command, string_name);
104dmidecode_pipe = popen(commandline, "r");
105if (!dmidecode_pipe) {
106msg_perr("DMI pipe open error\n");
107return NULL;
108}
109
110/* Kill lines starting with '#', as recent dmidecode versions
111 * have the quirk to emit a "# SMBIOS implementations newer..."
112 * message even on "-s" if the SMBIOS declares a
113 * newer-than-supported version number, while it *should* only print
114 * the requested string.
115 */
116do {
117if (!fgets(answerbuf, DMI_MAX_ANSWER_LEN, dmidecode_pipe)) {
118if (ferror(dmidecode_pipe)) {
119msg_perr("DMI pipe read error\n");
120pclose(dmidecode_pipe);
121return NULL;
122} else {
123answerbuf[0] = 0;/* Hit EOF */
124}
125}
126} while (answerbuf[0] == '#');
127
128/* Toss all output above DMI_MAX_ANSWER_LEN away to prevent
129 deadlock on pclose. */
130while (!feof(dmidecode_pipe))
131getc(dmidecode_pipe);
132if (pclose(dmidecode_pipe) != 0) {
133msg_pinfo("dmidecode execution unsuccessful - continuing "
134 "without DMI info\n");
135return NULL;
136}
137
138/* Chomp trailing newline. */
139if (answerbuf[0] != 0 && answerbuf[strlen(answerbuf) - 1] == '\n')
140answerbuf[strlen(answerbuf) - 1] = 0;
141msg_pdbg("DMI string %s: \"%s\"\n", string_name, answerbuf);
142
143result = strdup(answerbuf);
144if (!result)
145puts("WARNING: Out of memory - DMI support fails");
146
147return result;
148}
149
150void dmi_init(void)
151{
152int i;
153char *chassis_type;
154
155has_dmi_support = 1;
156for (i = 0; i < ARRAY_SIZE(dmidecode_names); i++) {
157dmistrings[i] = get_dmi_string(dmidecode_names[i]);
158if (!dmistrings[i]) {
159has_dmi_support = 0;
160return;
161}
162}
163
164chassis_type = get_dmi_string("chassis-type");
165if (chassis_type == NULL)
166return;
167
168is_laptop = 2;
169for (i = 0; i < ARRAY_SIZE(dmi_chassis_types); i++) {
170if (strcasecmp(chassis_type, dmi_chassis_types[i].name) == 0) {
171is_laptop = dmi_chassis_types[i].is_laptop;
172break;
173}
174}
175
176switch (is_laptop) {
177case 1:
178msg_pdbg("Laptop detected via DMI.\n");
179break;
180case 2:
181msg_pdbg("DMI chassis-type is not specific enough.\n");
182break;
183}
184free(chassis_type);
185}
186
187/**
188 * Does an substring/prefix/postfix/whole-string match.
189 *
190 * The pattern is matched as-is. The only metacharacters supported are '^'
191 * at the beginning and '$' at the end. So you can look for "^prefix",
192 * "suffix$", "substring" or "^complete string$".
193 *
194 * @param value The string to check.
195 * @param pattern The pattern.
196 * @return Nonzero if pattern matches.
197 */
198static int dmi_compare(const char *value, const char *pattern)
199{
200int anchored = 0;
201int patternlen;
202
203msg_pspew("matching %s against %s\n", value, pattern);
204/* The empty string is part of all strings! */
205if (pattern[0] == 0)
206return 1;
207
208if (pattern[0] == '^') {
209anchored = 1;
210pattern++;
211}
212
213patternlen = strlen(pattern);
214if (pattern[patternlen - 1] == '$') {
215int valuelen = strlen(value);
216patternlen--;
217if (patternlen > valuelen)
218return 0;
219
220/* full string match: require same length */
221if (anchored && (valuelen != patternlen))
222return 0;
223
224/* start character to make ends match */
225value += valuelen - patternlen;
226anchored = 1;
227}
228
229if (anchored)
230return strncmp(value, pattern, patternlen) == 0;
231else
232return strstr(value, pattern) != NULL;
233}
234
235int dmi_match(const char *pattern)
236{
237int i;
238
239if (!has_dmi_support)
240return 0;
241
242for (i = 0; i < ARRAY_SIZE(dmidecode_names); i++)
243if (dmi_compare(dmistrings[i], pattern))
244return 1;
245
246return 0;
247}
248
249#endif /* STANDALONE */
250

Archive Download this file

Revision: HEAD