1
2
3
4
5
6
7
8
9
10
11
12
13
14#include <stdio.h>
15#include <ctype.h>
16#include <string.h>
17#include <time.h>
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <fcntl.h>
21#include <unistd.h>
22#include <errno.h>
23
24#include "blkidP.h"
25#include "../uuid/uuid.h"
26
27#ifdef HAVE_STRTOULL
28#define __USE_ISOC9X
29#define STRTOULL strtoull
30#else
31
32#define STRTOULL strtoul
33#endif
34
35#include <stdlib.h>
36
37#ifdef TEST_PROGRAM
38#define blkid_debug_dump_dev(dev) (debug_dump_dev(dev))
39static void debug_dump_dev(blkid_dev dev);
40#endif
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57static char *skip_over_blank(char *cp)
58{
59 while (*cp && isspace(*cp))
60 cp++;
61 return cp;
62}
63
64static char *skip_over_word(char *cp)
65{
66 char ch;
67
68 while ((ch = *cp)) {
69
70 if (ch == '\\') {
71 cp++;
72 if (*cp == '\0')
73 break;
74 cp++;
75 continue;
76 }
77 if (isspace(ch) || ch == '<' || ch == '>')
78 break;
79 cp++;
80 }
81 return cp;
82}
83
84static char *strip_line(char *line)
85{
86 char *p;
87
88 line = skip_over_blank(line);
89
90 p = line + strlen(line) - 1;
91
92 while (*line) {
93 if (isspace(*p))
94 *p-- = '\0';
95 else
96 break;
97 }
98
99 return line;
100}
101
102
103
104
105
106
107
108
109static int parse_start(char **cp)
110{
111 char *p;
112
113 p = strip_line(*cp);
114
115
116
117
118 if (*p == '\0' || *p == '#')
119 return 0;
120
121 if (!strncmp(p, "<device", 7)) {
122 DBG(DEBUG_READ, printf("found device header: %8s\n", p));
123 p += 7;
124
125 *cp = p;
126 return 1;
127 }
128
129 if (*p == '<')
130 return 0;
131
132 return -BLKID_ERR_CACHE;
133}
134
135
136static int parse_end(char **cp)
137{
138 *cp = skip_over_blank(*cp);
139
140 if (!strncmp(*cp, "</device>", 9)) {
141 DBG(DEBUG_READ, printf("found device trailer %9s\n", *cp));
142 *cp += 9;
143 return 0;
144 }
145
146 return -BLKID_ERR_CACHE;
147}
148
149
150
151
152
153
154
155static int parse_dev(blkid_cache cache, blkid_dev *dev, char **cp)
156{
157 char *start, *tmp, *end, *name;
158 int ret;
159
160 if ((ret = parse_start(cp)) <= 0)
161 return ret;
162
163 start = tmp = strchr(*cp, '>');
164 if (!start) {
165 DBG(DEBUG_READ,
166 printf("blkid: short line parsing dev: %s\n", *cp));
167 return -BLKID_ERR_CACHE;
168 }
169 start = skip_over_blank(start + 1);
170 end = skip_over_word(start);
171
172 DBG(DEBUG_READ, printf("device should be %*s\n", end - start, start));
173
174 if (**cp == '>')
175 *cp = end;
176 else
177 (*cp)++;
178
179 *tmp = '\0';
180
181 if (!(tmp = strrchr(end, '<')) || parse_end(&tmp) < 0) {
182 DBG(DEBUG_READ,
183 printf("blkid: missing </device> ending: %s\n", end));
184 } else if (tmp)
185 *tmp = '\0';
186
187 if (end - start <= 1) {
188 DBG(DEBUG_READ, printf("blkid: empty device name: %s\n", *cp));
189 return -BLKID_ERR_CACHE;
190 }
191
192 name = blkid_strndup(start, end-start);
193 if (name == NULL)
194 return -BLKID_ERR_MEM;
195
196 DBG(DEBUG_READ, printf("found dev %s\n", name));
197
198 if (!(*dev = blkid_get_dev(cache, name, BLKID_DEV_CREATE)))
199 return -BLKID_ERR_MEM;
200
201 free(name);
202 return 1;
203}
204
205
206
207
208static int parse_token(char **name, char **value, char **cp)
209{
210 char *end;
211
212 if (!name || !value || !cp)
213 return -BLKID_ERR_PARAM;
214
215 if (!(*value = strchr(*cp, '=')))
216 return 0;
217
218 **value = '\0';
219 *name = strip_line(*cp);
220 *value = skip_over_blank(*value + 1);
221
222 if (**value == '"') {
223 end = strchr(*value + 1, '"');
224 if (!end) {
225 DBG(DEBUG_READ,
226 printf("unbalanced quotes at: %s\n", *value));
227 *cp = *value;
228 return -BLKID_ERR_CACHE;
229 }
230 (*value)++;
231 *end = '\0';
232 end++;
233 } else {
234 end = skip_over_word(*value);
235 if (*end) {
236 *end = '\0';
237 end++;
238 }
239 }
240 *cp = end;
241
242 return 1;
243}
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272static int parse_tag(blkid_cache cache, blkid_dev dev, char **cp)
273{
274 char *name;
275 char *value;
276 int ret;
277
278 if (!cache || !dev)
279 return -BLKID_ERR_PARAM;
280
281 if ((ret = parse_token(&name, &value, cp)) <= 0
282)
283 return ret;
284
285
286 if (!strcmp(name, "DEVNO"))
287 dev->bid_devno = STRTOULL(value, 0, 0);
288 else if (!strcmp(name, "PRI"))
289 dev->bid_pri = strtol(value, 0, 0);
290 else if (!strcmp(name, "TIME"))
291
292 dev->bid_time = strtol(value, 0, 0);
293 else
294 ret = blkid_set_tag(dev, name, value, strlen(value));
295
296 DBG(DEBUG_READ, printf(" tag: %s=\"%s\"\n", name, value));
297
298 return ret < 0 ? ret : 1;
299}
300
301
302
303
304
305
306
307
308
309
310
311
312static int blkid_parse_line(blkid_cache cache, blkid_dev *dev_p, char *cp)
313{
314 blkid_dev dev;
315 int ret;
316
317 if (!cache || !dev_p)
318 return -BLKID_ERR_PARAM;
319
320 *dev_p = NULL;
321
322 DBG(DEBUG_READ, printf("line: %s\n", cp));
323
324 if ((ret = parse_dev(cache, dev_p, &cp)) <= 0)
325 return ret;
326
327 dev = *dev_p;
328
329 while ((ret = parse_tag(cache, dev, &cp)) > 0) {
330 ;
331 }
332
333 if (dev->bid_type == NULL) {
334 DBG(DEBUG_READ,
335 printf("blkid: device %s has no TYPE\n",dev->bid_name));
336 blkid_free_dev(dev);
337 }
338
339 DBG(DEBUG_READ, blkid_debug_dump_dev(dev));
340
341 return ret;
342}
343
344
345
346
347
348
349void blkid_read_cache(blkid_cache cache)
350{
351 FILE *file;
352 char buf[4096];
353 int fd, lineno = 0;
354 struct stat st;
355
356 if (!cache)
357 return;
358
359
360
361
362
363 if ((fd = open(cache->bic_filename, O_RDONLY)) < 0)
364 return;
365 if (fstat(fd, &st) < 0)
366 goto errout;
367 if ((st.st_mtime == cache->bic_ftime) ||
368 (cache->bic_flags & BLKID_BIC_FL_CHANGED)) {
369 DBG(DEBUG_CACHE, printf("skipping re-read of %s\n",
370 cache->bic_filename));
371 goto errout;
372 }
373
374 DBG(DEBUG_CACHE, printf("reading cache file %s\n",
375 cache->bic_filename));
376
377 file = xfdopen_for_read(fd);
378
379 while (fgets(buf, sizeof(buf), file)) {
380 blkid_dev dev;
381 unsigned int end;
382
383 lineno++;
384 if (buf[0] == 0)
385 continue;
386 end = strlen(buf) - 1;
387
388 while (buf[end] == '\\' && end < sizeof(buf) - 2 &&
389 fgets(buf + end, sizeof(buf) - end, file)) {
390 end = strlen(buf) - 1;
391 lineno++;
392 }
393
394 if (blkid_parse_line(cache, &dev, buf) < 0) {
395 DBG(DEBUG_READ,
396 printf("blkid: bad format on line %d\n", lineno));
397 continue;
398 }
399 }
400 fclose(file);
401
402
403
404
405 cache->bic_flags &= ~BLKID_BIC_FL_CHANGED;
406 cache->bic_ftime = st.st_mtime;
407
408 return;
409errout:
410 close(fd);
411}
412
413#ifdef TEST_PROGRAM
414static void debug_dump_dev(blkid_dev dev)
415{
416 struct list_head *p;
417
418 if (!dev) {
419 printf(" dev: NULL\n");
420 return;
421 }
422
423 printf(" dev: name = %s\n", dev->bid_name);
424 printf(" dev: DEVNO=\"0x%0llx\"\n", dev->bid_devno);
425 printf(" dev: TIME=\"%lu\"\n", dev->bid_time);
426 printf(" dev: PRI=\"%d\"\n", dev->bid_pri);
427 printf(" dev: flags = 0x%08X\n", dev->bid_flags);
428
429 list_for_each(p, &dev->bid_tags) {
430 blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags);
431 if (tag)
432 printf(" tag: %s=\"%s\"\n", tag->bit_name,
433 tag->bit_val);
434 else
435 printf(" tag: NULL\n");
436 }
437 bb_putchar('\n');
438}
439
440int main(int argc, char**argv)
441{
442 blkid_cache cache = NULL;
443 int ret;
444
445 blkid_debug_mask = DEBUG_ALL;
446 if (argc > 2) {
447 fprintf(stderr, "Usage: %s [filename]\n"
448 "Test parsing of the cache (filename)\n", argv[0]);
449 exit(1);
450 }
451 if ((ret = blkid_get_cache(&cache, argv[1])) < 0)
452 fprintf(stderr, "error %d reading cache file %s\n", ret,
453 argv[1] ? argv[1] : BLKID_CACHE_FILE);
454
455 blkid_put_cache(cache);
456
457 return ret;
458}
459#endif
460