blob: 836b38b5cc55c1332325ffa93b3fac9598114b24 [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"
Carl-Daniel Hailfinger5b997c32010-07-27 22:41:39 +000026#include "programmer.h"
Michael Karcher6701ee82010-01-20 14:14:11 +000027
Carl-Daniel Hailfingere1fdff42010-06-23 23:14:44 +000028int 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{
43 return 0;
44}
45
46#else /* STANDALONE */
47
Carl-Daniel Hailfingerad3cc552010-07-03 11:02:10 +000048static const char *dmidecode_names[] = {
Michael Karcherf6498d72010-02-24 22:43:44 +000049 "system-manufacturer",
50 "system-product-name",
51 "system-version",
52 "baseboard-manufacturer",
53 "baseboard-product-name",
Uwe Hermann43959702010-03-13 17:28:29 +000054 "baseboard-version",
Michael Karcher6701ee82010-01-20 14:14:11 +000055};
56
Carl-Daniel Hailfingercb3eb052010-09-26 21:43:53 +000057/* A full list of chassis types can be found in the System Management BIOS
58 * (SMBIOS) Reference Specification 2.7.0 section 7.4.1 "Chassis Types" at
59 * http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.0.pdf
60 * The types below are the most common ones.
61 */
62static const struct {
63 unsigned char type;
64 unsigned char is_laptop;
65 const char *name;
66} dmi_chassis_types[] = {
67 {0x01, 0, "Other"},
68 {0x02, 0, "Unknown"},
69 {0x03, 0, "Desktop",},
70 {0x08, 1, "Portable"},
71 {0x09, 1, "Laptop"},
72 {0x0a, 1, "Notebook"},
73 {0x0b, 1, "Hand Held"},
74 {0x0e, 1, "Sub Notebook"},
75};
76
Michael Karcher6701ee82010-01-20 14:14:11 +000077#define DMI_COMMAND_LEN_MAX 260
Carl-Daniel Hailfingerad3cc552010-07-03 11:02:10 +000078static const char *dmidecode_command = "dmidecode";
Michael Karcher6701ee82010-01-20 14:14:11 +000079
Carl-Daniel Hailfingerad3cc552010-07-03 11:02:10 +000080static char *dmistrings[ARRAY_SIZE(dmidecode_names)];
Michael Karcher6701ee82010-01-20 14:14:11 +000081
Uwe Hermann43959702010-03-13 17:28:29 +000082/* Strings longer than 4096 in DMI are just insane. */
Michael Karcher6701ee82010-01-20 14:14:11 +000083#define DMI_MAX_ANSWER_LEN 4096
84
Michael Karcher0d7fb7c2010-02-26 09:51:16 +000085static char *get_dmi_string(const char *string_name)
Michael Karcher6701ee82010-01-20 14:14:11 +000086{
87 FILE *dmidecode_pipe;
Michael Karcher0d7fb7c2010-02-26 09:51:16 +000088 char *result;
89 char answerbuf[DMI_MAX_ANSWER_LEN];
Uwe Hermann43959702010-03-13 17:28:29 +000090 char commandline[DMI_COMMAND_LEN_MAX + 40];
91
Michael Karcher0d7fb7c2010-02-26 09:51:16 +000092 snprintf(commandline, sizeof(commandline),
93 "%s -s %s", dmidecode_command, string_name);
94 dmidecode_pipe = popen(commandline, "r");
95 if (!dmidecode_pipe) {
Sean Nelson316a29f2010-05-07 20:09:04 +000096 msg_perr("DMI pipe open error\n");
Michael Karcher0d7fb7c2010-02-26 09:51:16 +000097 return NULL;
Michael Karcher6701ee82010-01-20 14:14:11 +000098 }
Michael Karcherd9f266d2010-08-08 21:56:52 +000099
100 /* Kill lines starting with '#', as recent dmidecode versions
101 have the quirk to emit a "# SMBIOS implementations newer..."
102 message even on "-s" if the SMBIOS declares a
103 newer-than-supported version number, while it *should* only print
104 the requested string. */
105 do {
106 if (!fgets(answerbuf, DMI_MAX_ANSWER_LEN, dmidecode_pipe)) {
107 if(ferror(dmidecode_pipe)) {
108 msg_perr("DMI pipe read error\n");
109 pclose(dmidecode_pipe);
110 return NULL;
111 } else {
112 answerbuf[0] = 0; /* Hit EOF */
113 }
Michael Karcher45f79cb2010-03-24 17:55:04 +0000114 }
Michael Karcherd9f266d2010-08-08 21:56:52 +0000115 } while(answerbuf[0] == '#');
116
Michael Karcher0d7fb7c2010-02-26 09:51:16 +0000117 /* Toss all output above DMI_MAX_ANSWER_LEN away to prevent
118 deadlock on pclose. */
119 while (!feof(dmidecode_pipe))
120 getc(dmidecode_pipe);
121 if (pclose(dmidecode_pipe) != 0) {
Cristian Măgherușan-Stanciu9932c7b2011-07-07 19:56:58 +0000122 msg_pinfo("dmidecode execution unsuccessful - continuing "
Sean Nelson316a29f2010-05-07 20:09:04 +0000123 "without DMI info\n");
Michael Karcher0d7fb7c2010-02-26 09:51:16 +0000124 return NULL;
125 }
Michael Karcher6701ee82010-01-20 14:14:11 +0000126
Uwe Hermann43959702010-03-13 17:28:29 +0000127 /* Chomp trailing newline. */
Michael Karcher0d7fb7c2010-02-26 09:51:16 +0000128 if (answerbuf[0] != 0 &&
129 answerbuf[strlen(answerbuf) - 1] == '\n')
130 answerbuf[strlen(answerbuf) - 1] = 0;
Sean Nelson316a29f2010-05-07 20:09:04 +0000131 msg_pdbg("DMI string %s: \"%s\"\n", string_name, answerbuf);
Michael Karcher0d7fb7c2010-02-26 09:51:16 +0000132
133 result = strdup(answerbuf);
134 if (!result)
135 puts("WARNING: Out of memory - DMI support fails");
136
137 return result;
138}
139
140void dmi_init(void)
141{
142 int i;
Michael Karcher8c1df282010-02-26 09:51:20 +0000143 char *chassis_type;
Uwe Hermann43959702010-03-13 17:28:29 +0000144
Michael Karcher6701ee82010-01-20 14:14:11 +0000145 has_dmi_support = 1;
Michael Karcherfd416702010-03-14 17:57:52 +0000146 for (i = 0; i < ARRAY_SIZE(dmidecode_names); i++) {
Michael Karcher0d7fb7c2010-02-26 09:51:16 +0000147 dmistrings[i] = get_dmi_string(dmidecode_names[i]);
148 if (!dmistrings[i]) {
149 has_dmi_support = 0;
Michael Karcherfd416702010-03-14 17:57:52 +0000150 return;
Michael Karcher0d7fb7c2010-02-26 09:51:16 +0000151 }
152 }
Michael Karcher8c1df282010-02-26 09:51:20 +0000153
154 chassis_type = get_dmi_string("chassis-type");
Carl-Daniel Hailfingercb3eb052010-09-26 21:43:53 +0000155 if (chassis_type) {
156 for (i = 0; i < ARRAY_SIZE(dmi_chassis_types); i++) {
157 if (!strcasecmp(chassis_type,
158 dmi_chassis_types[i].name) &&
159 dmi_chassis_types[i].is_laptop) {
160 msg_pdbg("Laptop detected via DMI\n");
161 is_laptop = 1;
162 }
163 }
Michael Karcher8c1df282010-02-26 09:51:20 +0000164 }
165 free(chassis_type);
Michael Karcher6701ee82010-01-20 14:14:11 +0000166}
167
168/**
169 * Does an substring/prefix/postfix/whole-string match.
170 *
171 * The pattern is matched as-is. The only metacharacters supported are '^'
172 * at the beginning and '$' at the end. So you can look for "^prefix",
173 * "suffix$", "substring" or "^complete string$".
174 *
175 * @param value The string to check.
176 * @param pattern The pattern.
177 * @return Nonzero if pattern matches.
178 */
179static int dmi_compare(const char *value, const char *pattern)
180{
181 int anchored = 0;
182 int patternlen;
Uwe Hermann43959702010-03-13 17:28:29 +0000183
Sean Nelson316a29f2010-05-07 20:09:04 +0000184 msg_pspew("matching %s against %s\n", value, pattern);
Uwe Hermann43959702010-03-13 17:28:29 +0000185 /* The empty string is part of all strings! */
Michael Karcher6701ee82010-01-20 14:14:11 +0000186 if (pattern[0] == 0)
187 return 1;
188
189 if (pattern[0] == '^') {
190 anchored = 1;
191 pattern++;
192 }
193
194 patternlen = strlen(pattern);
195 if (pattern[patternlen - 1] == '$') {
196 int valuelen = strlen(value);
197 patternlen--;
Uwe Hermann43959702010-03-13 17:28:29 +0000198 if (patternlen > valuelen)
Michael Karcher6701ee82010-01-20 14:14:11 +0000199 return 0;
200
201 /* full string match: require same length */
Uwe Hermann43959702010-03-13 17:28:29 +0000202 if (anchored && (valuelen != patternlen))
Michael Karcher6701ee82010-01-20 14:14:11 +0000203 return 0;
204
205 /* start character to make ends match */
206 value += valuelen - patternlen;
207 anchored = 1;
208 }
209
210 if (anchored)
211 return strncmp(value, pattern, patternlen) == 0;
212 else
213 return strstr(value, pattern) != NULL;
214}
215
216int dmi_match(const char *pattern)
217{
218 int i;
Uwe Hermann43959702010-03-13 17:28:29 +0000219
Michael Karcher6701ee82010-01-20 14:14:11 +0000220 if (!has_dmi_support)
221 return 0;
222
Michael Karcherfd416702010-03-14 17:57:52 +0000223 for (i = 0; i < ARRAY_SIZE(dmidecode_names); i++)
Uwe Hermann43959702010-03-13 17:28:29 +0000224 if (dmi_compare(dmistrings[i], pattern))
Michael Karcher4dfa0932010-02-12 05:44:18 +0000225 return 1;
Michael Karcher6701ee82010-01-20 14:14:11 +0000226
227 return 0;
228}
Carl-Daniel Hailfingere1fdff42010-06-23 23:14:44 +0000229
230#endif /* STANDALONE */