blob: 242889f60043a08229dceb901d92e866a6e02854 [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
Carl-Daniel Hailfinger1c6d2ff2012-08-27 00:44:42 +000021#include <strings.h>
Michael Karcher6701ee82010-01-20 14:14:11 +000022#include <string.h>
23#include <stdio.h>
24#include <stdlib.h>
25
26#include "flash.h"
Carl-Daniel Hailfinger5b997c32010-07-27 22:41:39 +000027#include "programmer.h"
Michael Karcher6701ee82010-01-20 14:14:11 +000028
Carl-Daniel Hailfingere1fdff42010-06-23 23:14:44 +000029int has_dmi_support = 0;
30
31#if STANDALONE
32
33/* Stub to indicate missing DMI functionality.
34 * has_dmi_support is 0 by default, so nothing to do here.
35 * Because dmidecode is not available on all systems, the goal is to implement
36 * the DMI subset we need directly in this file.
37 */
38void dmi_init(void)
39{
40}
41
42int dmi_match(const char *pattern)
43{
44 return 0;
45}
46
47#else /* STANDALONE */
48
Carl-Daniel Hailfingerad3cc552010-07-03 11:02:10 +000049static const char *dmidecode_names[] = {
Michael Karcherf6498d72010-02-24 22:43:44 +000050 "system-manufacturer",
51 "system-product-name",
52 "system-version",
53 "baseboard-manufacturer",
54 "baseboard-product-name",
Uwe Hermann43959702010-03-13 17:28:29 +000055 "baseboard-version",
Michael Karcher6701ee82010-01-20 14:14:11 +000056};
57
Stefan Taunera34d7192011-07-26 00:54:42 +000058/* This list is used to identify supposed laptops. The is_laptop field has the
59 * following meaning:
60 * - 0: in all likelihood not a laptop
61 * - 1: in all likelihood a laptop
62 * - 2: chassis-type is not specific enough
63 * A full list of chassis types can be found in the System Management BIOS
Carl-Daniel Hailfingercb3eb052010-09-26 21:43:53 +000064 * (SMBIOS) Reference Specification 2.7.0 section 7.4.1 "Chassis Types" at
65 * http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.0.pdf
66 * The types below are the most common ones.
67 */
68static const struct {
69 unsigned char type;
70 unsigned char is_laptop;
71 const char *name;
72} dmi_chassis_types[] = {
Stefan Taunera34d7192011-07-26 00:54:42 +000073 {0x01, 2, "Other"},
74 {0x02, 2, "Unknown"},
Stefan Tauner4c5665f2012-02-17 20:03:37 +000075 {0x03, 0, "Desktop"},
76 {0x04, 0, "Low Profile Desktop"},
Stefan Taunera34d7192011-07-26 00:54:42 +000077 {0x06, 0, "Mini Tower"},
78 {0x07, 0, "Tower"},
Carl-Daniel Hailfingercb3eb052010-09-26 21:43:53 +000079 {0x08, 1, "Portable"},
80 {0x09, 1, "Laptop"},
81 {0x0a, 1, "Notebook"},
82 {0x0b, 1, "Hand Held"},
83 {0x0e, 1, "Sub Notebook"},
Stefan Taunera34d7192011-07-26 00:54:42 +000084 {0x11, 0, "Main Server Chassis"},
85 {0x17, 0, "Rack Mount Chassis"},
Sylvain "ythier" Hitier3093f8f2011-09-03 11:22:27 +000086 {0x18, 0, "Sealed-case PC"}, /* used by Supermicro (X8SIE) */
Carl-Daniel Hailfingercb3eb052010-09-26 21:43:53 +000087};
88
Michael Karcher6701ee82010-01-20 14:14:11 +000089#define DMI_COMMAND_LEN_MAX 260
Carl-Daniel Hailfingerad3cc552010-07-03 11:02:10 +000090static const char *dmidecode_command = "dmidecode";
Michael Karcher6701ee82010-01-20 14:14:11 +000091
Carl-Daniel Hailfingerad3cc552010-07-03 11:02:10 +000092static char *dmistrings[ARRAY_SIZE(dmidecode_names)];
Michael Karcher6701ee82010-01-20 14:14:11 +000093
Uwe Hermann43959702010-03-13 17:28:29 +000094/* Strings longer than 4096 in DMI are just insane. */
Michael Karcher6701ee82010-01-20 14:14:11 +000095#define DMI_MAX_ANSWER_LEN 4096
96
Michael Karcher0d7fb7c2010-02-26 09:51:16 +000097static char *get_dmi_string(const char *string_name)
Michael Karcher6701ee82010-01-20 14:14:11 +000098{
99 FILE *dmidecode_pipe;
Michael Karcher0d7fb7c2010-02-26 09:51:16 +0000100 char *result;
101 char answerbuf[DMI_MAX_ANSWER_LEN];
Uwe Hermann43959702010-03-13 17:28:29 +0000102 char commandline[DMI_COMMAND_LEN_MAX + 40];
103
Michael Karcher0d7fb7c2010-02-26 09:51:16 +0000104 snprintf(commandline, sizeof(commandline),
105 "%s -s %s", dmidecode_command, string_name);
106 dmidecode_pipe = popen(commandline, "r");
107 if (!dmidecode_pipe) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000108 msg_perr("Opening DMI pipe failed!\n");
Michael Karcher0d7fb7c2010-02-26 09:51:16 +0000109 return NULL;
Michael Karcher6701ee82010-01-20 14:14:11 +0000110 }
Michael Karcherd9f266d2010-08-08 21:56:52 +0000111
112 /* Kill lines starting with '#', as recent dmidecode versions
Uwe Hermann91f4afa2011-07-28 08:13:25 +0000113 * have the quirk to emit a "# SMBIOS implementations newer..."
114 * message even on "-s" if the SMBIOS declares a
115 * newer-than-supported version number, while it *should* only print
116 * the requested string.
117 */
Michael Karcherd9f266d2010-08-08 21:56:52 +0000118 do {
119 if (!fgets(answerbuf, DMI_MAX_ANSWER_LEN, dmidecode_pipe)) {
Uwe Hermann91f4afa2011-07-28 08:13:25 +0000120 if (ferror(dmidecode_pipe)) {
Michael Karcherd9f266d2010-08-08 21:56:52 +0000121 msg_perr("DMI pipe read error\n");
122 pclose(dmidecode_pipe);
123 return NULL;
124 } else {
125 answerbuf[0] = 0; /* Hit EOF */
126 }
Michael Karcher45f79cb2010-03-24 17:55:04 +0000127 }
Uwe Hermann91f4afa2011-07-28 08:13:25 +0000128 } while (answerbuf[0] == '#');
Michael Karcherd9f266d2010-08-08 21:56:52 +0000129
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000130 /* Discard all output exceeding DMI_MAX_ANSWER_LEN to prevent deadlock on pclose. */
Michael Karcher0d7fb7c2010-02-26 09:51:16 +0000131 while (!feof(dmidecode_pipe))
132 getc(dmidecode_pipe);
133 if (pclose(dmidecode_pipe) != 0) {
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000134 msg_pwarn("dmidecode execution unsuccessful - continuing without DMI info\n");
Michael Karcher0d7fb7c2010-02-26 09:51:16 +0000135 return NULL;
136 }
Michael Karcher6701ee82010-01-20 14:14:11 +0000137
Uwe Hermann43959702010-03-13 17:28:29 +0000138 /* Chomp trailing newline. */
Uwe Hermann91f4afa2011-07-28 08:13:25 +0000139 if (answerbuf[0] != 0 && answerbuf[strlen(answerbuf) - 1] == '\n')
Michael Karcher0d7fb7c2010-02-26 09:51:16 +0000140 answerbuf[strlen(answerbuf) - 1] = 0;
Sean Nelson316a29f2010-05-07 20:09:04 +0000141 msg_pdbg("DMI string %s: \"%s\"\n", string_name, answerbuf);
Michael Karcher0d7fb7c2010-02-26 09:51:16 +0000142
143 result = strdup(answerbuf);
144 if (!result)
Stefan Taunerc6fa32d2013-01-04 22:54:07 +0000145 msg_pwarn("Warning: Out of memory - DMI support fails");
Michael Karcher0d7fb7c2010-02-26 09:51:16 +0000146
147 return result;
148}
149
Stefan Tauner4e6d3462012-09-23 12:14:28 +0000150static int dmi_shutdown(void *data)
151{
152 int i;
153 for (i = 0; i < ARRAY_SIZE(dmistrings); i++) {
154 free(dmistrings[i]);
155 dmistrings[i] = NULL;
156 }
157 return 0;
158}
159
Michael Karcher0d7fb7c2010-02-26 09:51:16 +0000160void dmi_init(void)
161{
162 int i;
Michael Karcher8c1df282010-02-26 09:51:20 +0000163 char *chassis_type;
Uwe Hermann43959702010-03-13 17:28:29 +0000164
Stefan Tauner4e6d3462012-09-23 12:14:28 +0000165 if (register_shutdown(dmi_shutdown, NULL))
166 return;
167
Michael Karcher6701ee82010-01-20 14:14:11 +0000168 has_dmi_support = 1;
Michael Karcherfd416702010-03-14 17:57:52 +0000169 for (i = 0; i < ARRAY_SIZE(dmidecode_names); i++) {
Michael Karcher0d7fb7c2010-02-26 09:51:16 +0000170 dmistrings[i] = get_dmi_string(dmidecode_names[i]);
171 if (!dmistrings[i]) {
172 has_dmi_support = 0;
Michael Karcherfd416702010-03-14 17:57:52 +0000173 return;
Michael Karcher0d7fb7c2010-02-26 09:51:16 +0000174 }
175 }
Michael Karcher8c1df282010-02-26 09:51:20 +0000176
177 chassis_type = get_dmi_string("chassis-type");
Stefan Taunera34d7192011-07-26 00:54:42 +0000178 if (chassis_type == NULL)
179 return;
180
181 is_laptop = 2;
182 for (i = 0; i < ARRAY_SIZE(dmi_chassis_types); i++) {
183 if (strcasecmp(chassis_type, dmi_chassis_types[i].name) == 0) {
184 is_laptop = dmi_chassis_types[i].is_laptop;
185 break;
Carl-Daniel Hailfingercb3eb052010-09-26 21:43:53 +0000186 }
Michael Karcher8c1df282010-02-26 09:51:20 +0000187 }
Stefan Taunera34d7192011-07-26 00:54:42 +0000188
189 switch (is_laptop) {
190 case 1:
191 msg_pdbg("Laptop detected via DMI.\n");
192 break;
193 case 2:
194 msg_pdbg("DMI chassis-type is not specific enough.\n");
195 break;
196 }
Michael Karcher8c1df282010-02-26 09:51:20 +0000197 free(chassis_type);
Michael Karcher6701ee82010-01-20 14:14:11 +0000198}
199
200/**
201 * Does an substring/prefix/postfix/whole-string match.
202 *
203 * The pattern is matched as-is. The only metacharacters supported are '^'
204 * at the beginning and '$' at the end. So you can look for "^prefix",
205 * "suffix$", "substring" or "^complete string$".
206 *
207 * @param value The string to check.
208 * @param pattern The pattern.
209 * @return Nonzero if pattern matches.
210 */
211static int dmi_compare(const char *value, const char *pattern)
212{
Carl-Daniel Hailfinger082c8b52011-08-15 19:54:20 +0000213 int anchored = 0;
214 int patternlen;
Uwe Hermann43959702010-03-13 17:28:29 +0000215
Sean Nelson316a29f2010-05-07 20:09:04 +0000216 msg_pspew("matching %s against %s\n", value, pattern);
Uwe Hermann43959702010-03-13 17:28:29 +0000217 /* The empty string is part of all strings! */
Michael Karcher6701ee82010-01-20 14:14:11 +0000218 if (pattern[0] == 0)
219 return 1;
220
221 if (pattern[0] == '^') {
222 anchored = 1;
223 pattern++;
224 }
225
226 patternlen = strlen(pattern);
227 if (pattern[patternlen - 1] == '$') {
228 int valuelen = strlen(value);
229 patternlen--;
Uwe Hermann43959702010-03-13 17:28:29 +0000230 if (patternlen > valuelen)
Michael Karcher6701ee82010-01-20 14:14:11 +0000231 return 0;
232
233 /* full string match: require same length */
Uwe Hermann43959702010-03-13 17:28:29 +0000234 if (anchored && (valuelen != patternlen))
Michael Karcher6701ee82010-01-20 14:14:11 +0000235 return 0;
236
237 /* start character to make ends match */
238 value += valuelen - patternlen;
239 anchored = 1;
240 }
241
242 if (anchored)
243 return strncmp(value, pattern, patternlen) == 0;
244 else
245 return strstr(value, pattern) != NULL;
246}
247
248int dmi_match(const char *pattern)
249{
250 int i;
Uwe Hermann43959702010-03-13 17:28:29 +0000251
Michael Karcher6701ee82010-01-20 14:14:11 +0000252 if (!has_dmi_support)
253 return 0;
254
Michael Karcherfd416702010-03-14 17:57:52 +0000255 for (i = 0; i < ARRAY_SIZE(dmidecode_names); i++)
Uwe Hermann43959702010-03-13 17:28:29 +0000256 if (dmi_compare(dmistrings[i], pattern))
Michael Karcher4dfa0932010-02-12 05:44:18 +0000257 return 1;
Michael Karcher6701ee82010-01-20 14:14:11 +0000258
259 return 0;
260}
Carl-Daniel Hailfingere1fdff42010-06-23 23:14:44 +0000261
262#endif /* STANDALONE */