/[soft]/ldetect/trunk/dmi.c
ViewVC logotype

Contents of /ldetect/trunk/dmi.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1357 - (show annotations) (download)
Tue May 17 09:21:22 2011 UTC (10 years, 1 month ago) by dmorgan
File MIME type: text/plain
File size: 7606 byte(s)
Import  ldetect
1 /* DMI (Desktop Management Interface)
2 also called
3 SMBIOS (System Management BIOS)
4 */
5
6 #define _GNU_SOURCE
7 #include <stdio.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include "common.h"
11
12 char *dmidecode_file = NULL;
13
14
15 static const char *cat_BIOS[] = { "Vendor", "Version" };
16 static const char *cat_System[] = { "Manufacturer", "Product Name", "Version" };
17 static const char *cat_Base_Board[] = { "Manufacturer", "Product Name", "Version" };
18
19 struct category {
20 const char *cat_name;
21 unsigned int nb_fields;
22 const char **fields;
23 };
24
25 static const struct category categories[] = {
26 { "BIOS", psizeof(cat_BIOS), cat_BIOS },
27 { "System", psizeof(cat_System), cat_System },
28 { "Base Board", psizeof(cat_Base_Board), cat_Base_Board },
29
30 };
31 static int nb_categories = psizeof(categories);
32
33 struct criterion {
34 char *name;
35 char *val;
36 };
37 struct criteria {
38 unsigned int nb;
39 struct criterion *criteria;
40 };
41
42 /*********************************************************************************/
43 static int streq(const char *s1, const char *s2) {
44 return strcmp(s1, s2) == 0;
45 }
46 static int str_begins_with(const char *s, const char *prefix) {
47 return strncmp(s, prefix, strlen(prefix)) == 0;
48 }
49 static int remove_suffix_in_place(char *s, const char *suffix) {
50 unsigned int l = strlen(s);
51 unsigned int l_suffix = strlen(suffix);
52 if (l >= l_suffix && streq(s + l - l_suffix, suffix)) {
53 s[l - l_suffix] = '\0';
54 return 1;
55 } else
56 return 0;
57 }
58 static void remove_ending_spaces(char *s) {
59 char *p;
60 for (p = s + strlen(s) - 1; p >= s; p--) {
61 if (*p != '\n' && *p != '\r' && *p != ' ' && *p != '\t')
62 break;
63 *p = '\0';
64 }
65 }
66 static char *skip_leading_spaces(char *s) {
67 for (; *s; s++)
68 if (*s != '\n' && *s != '\r' && *s != ' ' && *s != '\t')
69 break;
70 return s;
71 }
72
73 /*********************************************************************************/
74 static char *get_after_colon(char *s) {
75 char *p = strchr(s, ':');
76 if (p) {
77 *p = '\0';
78 return p + (p[1] == ' ' ? 2 : 1);
79 } else return NULL;
80 }
81
82 static const struct category *lookup_category(const char *cat_name) {
83 int i;
84 for (i = 0; i < nb_categories; i++)
85 if (streq(categories[i].cat_name, cat_name))
86 return &categories[i];
87 return NULL;
88 }
89
90 static int lookup_field(const struct category *category, const char *field_name) {
91 unsigned int i;
92 for (i = 0; i < category->nb_fields; i++)
93 if (streq(category->fields[i], field_name))
94 return 1;
95 return 0;
96 }
97
98 static char *lookup_criteria(struct criteria criteria, const char *field) {
99 unsigned int i;
100 for (i = 0; i < criteria.nb; i++)
101 if (streq(criteria.criteria[i].name, field))
102 return criteria.criteria[i].val;
103 return NULL;
104 }
105
106 /*********************************************************************************/
107 static struct criteria criteria_from_dmidecode(void) {
108 FILE *f;
109 char buf[BUF_SIZE];
110
111 struct criteria r = {0, NULL};
112
113 if (!(f = dmidecode_file ? fopen(dmidecode_file, "r") : popen("dmidecode", "r"))) {
114 perror("dmidecode");
115 return r;
116 }
117
118 r.criteria = malloc(sizeof(*r.criteria) * MAX_DEVICES);
119
120 const struct category *category = NULL;
121
122 /* dmidecode output is less indented as of 2.7 */
123 int tab_level = 1;
124 if (fgets(buf, sizeof(buf) - 1, f)) {
125 int major, minor;
126 if (sscanf(buf, "# dmidecode %d.%d", &major, &minor) == 2 && major >= 2 && minor >= 7)
127 tab_level = 0;
128 }
129
130 while (fgets(buf, sizeof(buf) - 1, f)) {
131 if (!buf[0] || !buf[1] || (tab_level && buf[0] != '\t'))
132 ; /* don't care */
133 else if (buf[tab_level] != '\t') {
134 char *s = buf + tab_level;
135 if (!str_begins_with(s, "DMI type ")) {
136 remove_ending_spaces(s);
137 remove_suffix_in_place(s, " Information");
138 category = lookup_category(s);
139 }
140 } else if (category) {
141 /* don't even look if we don't have an interesting category */
142 char *s = buf + tab_level + 1;
143 char *val = get_after_colon(s);
144 if (val && lookup_field(category, s)) {
145 struct criterion *criterion = &r.criteria[r.nb++];
146 asprintf(&criterion->name, "%s/%s", category->cat_name, s);
147 remove_ending_spaces(val);
148 criterion->val = strdup(skip_leading_spaces(val));
149 }
150 }
151 }
152 if (dmidecode_file ? fclose(f) != 0 : pclose(f) == -1) {
153 r.nb = 0;
154 return r;
155 }
156 r.criteria = realloc(r.criteria, sizeof(*r.criteria) * r.nb);
157
158 return r;
159 }
160
161 static void free_criteria(struct criteria criteria) {
162 unsigned int i;
163 for (i = 0; i < criteria.nb; i++) {
164 free(criteria.criteria[i].name);
165 free(criteria.criteria[i].val);
166 }
167 if (criteria.nb) free(criteria.criteria);
168 criteria.nb = 0;
169 }
170
171 static struct dmi_entries entries_matching_criteria(struct criteria criteria) {
172 fh f;
173 char buf[2048];
174 int line;
175 struct dmi_entries r;
176 #define MAX_INDENT 20
177 int valid[MAX_INDENT];
178 char *constraints[MAX_INDENT];
179
180 enum state { in_constraints, in_implies } state = in_implies;
181 int was_a_blank_line = 1;
182
183 r.nb = 0;
184 f = fh_open("dmitable");
185
186 #define die(err) do { fprintf(stderr, "%s %d: " err "\n", "dmitable", line); exit(1); } while (0)
187
188 r.entries = malloc(sizeof(*r.entries) * MAX_DEVICES);
189
190 #define foreach_indent(min, action) do { int i; for (i = min; i < MAX_INDENT; i++) { action; } } while (0)
191
192 foreach_indent(0, valid[i] = 1; constraints[i] = NULL);
193
194 int previous_refine = 0;
195
196 for (line = 1; fh_gets(buf, sizeof(buf) - 1, &f); line++) {
197 char *s = skip_leading_spaces(buf);
198 if (*s == '#') continue; // skip comments
199
200 if (!*s) {
201 was_a_blank_line = 1;
202 } else {
203 int refine = s - buf;
204 if (refine > MAX_INDENT) die("too indented constraints");
205
206 remove_ending_spaces(s);
207 if (str_begins_with(s, "=> ")) {
208 if (refine != previous_refine) die("\"=>\" must not be indented");
209 state = in_implies;
210 was_a_blank_line = 0;
211
212 if (valid[refine]) {
213 struct dmi_entry *entry = &r.entries[r.nb++];
214
215 s += strlen("=> ");
216 char *val = get_after_colon(s);
217 if (!val) die("invalid value");
218 asprintf(&entry->module, "%s:%s", s, val);
219
220 char tmp[BUF_SIZE];
221 tmp[0] = '\0';
222
223 int i;
224 for (i = 0; i <= refine; i++)
225 if (constraints[i]) {
226 if (i) strncat(tmp, "|", BUF_SIZE);
227 strncat(tmp, constraints[i], BUF_SIZE);
228 }
229 entry->constraints = strdup(tmp);
230 }
231 } else {
232 if (state == in_constraints && refine == previous_refine) die("to refine, indent");
233 if (!was_a_blank_line) die("missing empty line");
234 state = in_constraints;
235 previous_refine = refine;
236 was_a_blank_line = 0;
237
238 if (refine == 0 || valid[refine - 1]) {
239
240 char *wanted_val = get_after_colon(s);
241 if (!wanted_val) die("bad format");
242
243 char *wanted_val_orig = strdup(wanted_val);
244 char *val = lookup_criteria(criteria, s);
245
246 int ok = wanted_val && val && (
247 remove_suffix_in_place(wanted_val, ".*") ?
248 str_begins_with(val, wanted_val) :
249 streq(val, wanted_val));
250
251 foreach_indent(refine, valid[i] = ok; ifree(constraints[i]));
252 if (ok)
253 constraints[refine] = wanted_val_orig;
254 else
255 free(wanted_val_orig);
256
257 } /* otherwise no need checking */
258 }
259 }
260 }
261 foreach_indent(0, ifree(constraints[i]));
262 fh_close(&f);
263
264 r.entries = realloc(r.entries, sizeof(*r.entries) * r.nb);
265 return r;
266 }
267
268 extern void dmi_entries_free(struct dmi_entries entries) {
269 unsigned int i;
270 for (i = 0; i < entries.nb; i++) {
271 free(entries.entries[i].constraints);
272 free(entries.entries[i].module);
273 }
274 if (entries.nb) free(entries.entries);
275 entries.nb = 0;
276 }
277
278 extern struct dmi_entries dmi_probe(void) {
279 struct criteria criteria = criteria_from_dmidecode();
280 struct dmi_entries entries = entries_matching_criteria(criteria);
281 free_criteria(criteria);
282
283 return entries;
284 }
285

Properties

Name Value
svn:eol-style native

  ViewVC Help
Powered by ViewVC 1.1.28