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

Contents of /ldetect/trunk/dmi.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7092 - (show annotations) (download)
Mon Jan 14 20:24:32 2013 UTC (11 years, 3 months ago) by tv
File MIME type: text/plain
File size: 7960 byte(s)
dynamically resize memory when reaching max devices limit (mga#8320)
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 size_t allocated = MAX_DEVICES;
113
114 if (!(f = dmidecode_file ? fopen(dmidecode_file, "r") : popen("dmidecode", "r"))) {
115 perror("dmidecode");
116 return r;
117 }
118
119 r.criteria = malloc(sizeof(*r.criteria) * MAX_DEVICES);
120
121 const struct category *category = NULL;
122
123 /* dmidecode output is less indented as of 2.7 */
124 int tab_level = 1;
125 if (fgets(buf, sizeof(buf) - 1, f)) {
126 int major, minor;
127 if (sscanf(buf, "# dmidecode %d.%d", &major, &minor) == 2 && major >= 2 && minor >= 7)
128 tab_level = 0;
129 }
130
131 while (fgets(buf, sizeof(buf) - 1, f)) {
132 if (!buf[0] || !buf[1] || (tab_level && buf[0] != '\t'))
133 ; /* don't care */
134 else if (buf[tab_level] != '\t') {
135 char *s = buf + tab_level;
136 if (!str_begins_with(s, "DMI type ")) {
137 remove_ending_spaces(s);
138 remove_suffix_in_place(s, " Information");
139 category = lookup_category(s);
140 }
141 } else if (category) {
142 /* don't even look if we don't have an interesting category */
143 char *s = buf + tab_level + 1;
144 char *val = get_after_colon(s);
145 if (val && lookup_field(category, s)) {
146 if (r.nb >= allocated) {
147 allocated = r.nb*2;
148 r.criteria = realloc(r.criteria, sizeof(struct criterion) * allocated);
149 }
150 struct criterion *criterion = &r.criteria[r.nb++];
151 asprintf(&criterion->name, "%s/%s", category->cat_name, s);
152 remove_ending_spaces(val);
153 criterion->val = strdup(skip_leading_spaces(val));
154 }
155 }
156 }
157 if (dmidecode_file ? fclose(f) != 0 : pclose(f) == -1) {
158 r.nb = 0;
159 return r;
160 }
161 r.criteria = realloc(r.criteria, sizeof(*r.criteria) * r.nb);
162
163 return r;
164 }
165
166 static void free_criteria(struct criteria criteria) {
167 unsigned int i;
168 for (i = 0; i < criteria.nb; i++) {
169 free(criteria.criteria[i].name);
170 free(criteria.criteria[i].val);
171 }
172 if (criteria.nb) free(criteria.criteria);
173 criteria.nb = 0;
174 }
175
176 static struct dmi_entries entries_matching_criteria(struct criteria criteria) {
177 fh f;
178 char buf[2048];
179 int line;
180 struct dmi_entries r;
181 #define MAX_INDENT 20
182 int valid[MAX_INDENT];
183 char *constraints[MAX_INDENT];
184
185 enum state { in_constraints, in_implies } state = in_implies;
186 int was_a_blank_line = 1;
187 size_t allocated = MAX_DEVICES;
188
189 r.nb = 0;
190 f = fh_open("dmitable");
191
192 #define die(err) do { fprintf(stderr, "%s %d: " err "\n", "dmitable", line); exit(1); } while (0)
193
194 r.entries = malloc(sizeof(*r.entries) * MAX_DEVICES);
195
196 #define foreach_indent(min, action) do { int i; for (i = min; i < MAX_INDENT; i++) { action; } } while (0)
197
198 foreach_indent(0, valid[i] = 1; constraints[i] = NULL);
199
200 int previous_refine = 0;
201
202 for (line = 1; fh_gets(buf, sizeof(buf) - 1, &f); line++) {
203 char *s = skip_leading_spaces(buf);
204 if (*s == '#') continue; // skip comments
205
206 if (!*s) {
207 was_a_blank_line = 1;
208 } else {
209 int refine = s - buf;
210 if (refine > MAX_INDENT) die("too indented constraints");
211
212 remove_ending_spaces(s);
213 if (str_begins_with(s, "=> ")) {
214 if (refine != previous_refine) die("\"=>\" must not be indented");
215 state = in_implies;
216 was_a_blank_line = 0;
217
218 if (valid[refine]) {
219 if (r.nb >= allocated) {
220 allocated = r.nb*2;
221 r.entries = realloc(r.entries, sizeof(struct criterion) * allocated);
222 }
223 struct dmi_entry *entry = &r.entries[r.nb++];
224
225 s += strlen("=> ");
226 char *val = get_after_colon(s);
227 if (!val) die("invalid value");
228 asprintf(&entry->module, "%s:%s", s, val);
229
230 char tmp[BUF_SIZE];
231 tmp[0] = '\0';
232
233 int i;
234 for (i = 0; i <= refine; i++)
235 if (constraints[i]) {
236 if (i) strncat(tmp, "|", BUF_SIZE);
237 strncat(tmp, constraints[i], BUF_SIZE);
238 }
239 entry->constraints = strdup(tmp);
240 }
241 } else {
242 if (state == in_constraints && refine == previous_refine) die("to refine, indent");
243 if (!was_a_blank_line) die("missing empty line");
244 state = in_constraints;
245 previous_refine = refine;
246 was_a_blank_line = 0;
247
248 if (refine == 0 || valid[refine - 1]) {
249
250 char *wanted_val = get_after_colon(s);
251 if (!wanted_val) die("bad format");
252
253 char *wanted_val_orig = strdup(wanted_val);
254 char *val = lookup_criteria(criteria, s);
255
256 int ok = wanted_val && val && (
257 remove_suffix_in_place(wanted_val, ".*") ?
258 str_begins_with(val, wanted_val) :
259 streq(val, wanted_val));
260
261 foreach_indent(refine, valid[i] = ok; ifree(constraints[i]));
262 if (ok)
263 constraints[refine] = wanted_val_orig;
264 else
265 free(wanted_val_orig);
266
267 } /* otherwise no need checking */
268 }
269 }
270 }
271 foreach_indent(0, ifree(constraints[i]));
272 fh_close(&f);
273
274 r.entries = realloc(r.entries, sizeof(*r.entries) * r.nb);
275 return r;
276 }
277
278 extern void dmi_entries_free(struct dmi_entries entries) {
279 unsigned int i;
280 for (i = 0; i < entries.nb; i++) {
281 free(entries.entries[i].constraints);
282 free(entries.entries[i].module);
283 }
284 if (entries.nb) free(entries.entries);
285 entries.nb = 0;
286 }
287
288 extern struct dmi_entries dmi_probe(void) {
289 struct criteria criteria = criteria_from_dmidecode();
290 struct dmi_entries entries = entries_matching_criteria(criteria);
291 free_criteria(criteria);
292
293 return entries;
294 }
295

Properties

Name Value
svn:eol-style native

  ViewVC Help
Powered by ViewVC 1.1.30