xref: /aosp_15_r20/external/e2fsprogs/lib/blkid/read.c (revision 6a54128f25917bfc36a8a6e9d722c04a0b4641b6)
1*6a54128fSAndroid Build Coastguard Worker /*
2*6a54128fSAndroid Build Coastguard Worker  * read.c - read the blkid cache from disk, to avoid scanning all devices
3*6a54128fSAndroid Build Coastguard Worker  *
4*6a54128fSAndroid Build Coastguard Worker  * Copyright (C) 2001, 2003 Theodore Y. Ts'o
5*6a54128fSAndroid Build Coastguard Worker  * Copyright (C) 2001 Andreas Dilger
6*6a54128fSAndroid Build Coastguard Worker  *
7*6a54128fSAndroid Build Coastguard Worker  * %Begin-Header%
8*6a54128fSAndroid Build Coastguard Worker  * This file may be redistributed under the terms of the
9*6a54128fSAndroid Build Coastguard Worker  * GNU Lesser General Public License.
10*6a54128fSAndroid Build Coastguard Worker  * %End-Header%
11*6a54128fSAndroid Build Coastguard Worker  */
12*6a54128fSAndroid Build Coastguard Worker 
13*6a54128fSAndroid Build Coastguard Worker #define _XOPEN_SOURCE 600 /* for inclusion of strtoull */
14*6a54128fSAndroid Build Coastguard Worker 
15*6a54128fSAndroid Build Coastguard Worker #include "config.h"
16*6a54128fSAndroid Build Coastguard Worker #include <stdio.h>
17*6a54128fSAndroid Build Coastguard Worker #include <ctype.h>
18*6a54128fSAndroid Build Coastguard Worker #include <string.h>
19*6a54128fSAndroid Build Coastguard Worker #include <time.h>
20*6a54128fSAndroid Build Coastguard Worker #include <sys/types.h>
21*6a54128fSAndroid Build Coastguard Worker #include <sys/stat.h>
22*6a54128fSAndroid Build Coastguard Worker #include <fcntl.h>
23*6a54128fSAndroid Build Coastguard Worker #include <unistd.h>
24*6a54128fSAndroid Build Coastguard Worker #if HAVE_ERRNO_H
25*6a54128fSAndroid Build Coastguard Worker #include <errno.h>
26*6a54128fSAndroid Build Coastguard Worker #endif
27*6a54128fSAndroid Build Coastguard Worker 
28*6a54128fSAndroid Build Coastguard Worker #include "blkidP.h"
29*6a54128fSAndroid Build Coastguard Worker #include "uuid/uuid.h"
30*6a54128fSAndroid Build Coastguard Worker 
31*6a54128fSAndroid Build Coastguard Worker #ifdef HAVE_STRTOULL
32*6a54128fSAndroid Build Coastguard Worker #define STRTOULL strtoull /* defined in stdlib.h if you try hard enough */
33*6a54128fSAndroid Build Coastguard Worker #else
34*6a54128fSAndroid Build Coastguard Worker /* FIXME: need to support real strtoull here */
35*6a54128fSAndroid Build Coastguard Worker #define STRTOULL strtoul
36*6a54128fSAndroid Build Coastguard Worker #endif
37*6a54128fSAndroid Build Coastguard Worker 
38*6a54128fSAndroid Build Coastguard Worker #if HAVE_STDLIB_H
39*6a54128fSAndroid Build Coastguard Worker #include <stdlib.h>
40*6a54128fSAndroid Build Coastguard Worker #endif
41*6a54128fSAndroid Build Coastguard Worker 
42*6a54128fSAndroid Build Coastguard Worker #ifdef TEST_PROGRAM
43*6a54128fSAndroid Build Coastguard Worker #define blkid_debug_dump_dev(dev)	(debug_dump_dev(dev))
44*6a54128fSAndroid Build Coastguard Worker static void debug_dump_dev(blkid_dev dev);
45*6a54128fSAndroid Build Coastguard Worker #endif
46*6a54128fSAndroid Build Coastguard Worker 
47*6a54128fSAndroid Build Coastguard Worker /*
48*6a54128fSAndroid Build Coastguard Worker  * File format:
49*6a54128fSAndroid Build Coastguard Worker  *
50*6a54128fSAndroid Build Coastguard Worker  *	<device [<NAME="value"> ...]>device_name</device>
51*6a54128fSAndroid Build Coastguard Worker  *
52*6a54128fSAndroid Build Coastguard Worker  *	The following tags are required for each entry:
53*6a54128fSAndroid Build Coastguard Worker  *	<ID="id">	unique (within this file) ID number of this device
54*6a54128fSAndroid Build Coastguard Worker  *	<TIME="time">	(ascii time_t) time this entry was last read from disk
55*6a54128fSAndroid Build Coastguard Worker  *	<TYPE="type">	(detected) type of filesystem/data for this partition
56*6a54128fSAndroid Build Coastguard Worker  *
57*6a54128fSAndroid Build Coastguard Worker  *	The following tags may be present, depending on the device contents
58*6a54128fSAndroid Build Coastguard Worker  *	<LABEL="label">	(user supplied) label (volume name, etc)
59*6a54128fSAndroid Build Coastguard Worker  *	<UUID="uuid">	(generated) universally unique identifier (serial no)
60*6a54128fSAndroid Build Coastguard Worker  */
61*6a54128fSAndroid Build Coastguard Worker 
skip_over_blank(char * cp)62*6a54128fSAndroid Build Coastguard Worker static char *skip_over_blank(char *cp)
63*6a54128fSAndroid Build Coastguard Worker {
64*6a54128fSAndroid Build Coastguard Worker 	while (*cp && isspace(*cp))
65*6a54128fSAndroid Build Coastguard Worker 		cp++;
66*6a54128fSAndroid Build Coastguard Worker 	return cp;
67*6a54128fSAndroid Build Coastguard Worker }
68*6a54128fSAndroid Build Coastguard Worker 
skip_over_word(char * cp)69*6a54128fSAndroid Build Coastguard Worker static char *skip_over_word(char *cp)
70*6a54128fSAndroid Build Coastguard Worker {
71*6a54128fSAndroid Build Coastguard Worker 	char ch;
72*6a54128fSAndroid Build Coastguard Worker 
73*6a54128fSAndroid Build Coastguard Worker 	while ((ch = *cp)) {
74*6a54128fSAndroid Build Coastguard Worker 		/* If we see a backslash, skip the next character */
75*6a54128fSAndroid Build Coastguard Worker 		if (ch == '\\') {
76*6a54128fSAndroid Build Coastguard Worker 			cp++;
77*6a54128fSAndroid Build Coastguard Worker 			if (*cp == '\0')
78*6a54128fSAndroid Build Coastguard Worker 				break;
79*6a54128fSAndroid Build Coastguard Worker 			cp++;
80*6a54128fSAndroid Build Coastguard Worker 			continue;
81*6a54128fSAndroid Build Coastguard Worker 		}
82*6a54128fSAndroid Build Coastguard Worker 		if (isspace(ch) || ch == '<' || ch == '>')
83*6a54128fSAndroid Build Coastguard Worker 			break;
84*6a54128fSAndroid Build Coastguard Worker 		cp++;
85*6a54128fSAndroid Build Coastguard Worker 	}
86*6a54128fSAndroid Build Coastguard Worker 	return cp;
87*6a54128fSAndroid Build Coastguard Worker }
88*6a54128fSAndroid Build Coastguard Worker 
strip_line(char * line)89*6a54128fSAndroid Build Coastguard Worker static char *strip_line(char *line)
90*6a54128fSAndroid Build Coastguard Worker {
91*6a54128fSAndroid Build Coastguard Worker 	char	*p;
92*6a54128fSAndroid Build Coastguard Worker 
93*6a54128fSAndroid Build Coastguard Worker 	line = skip_over_blank(line);
94*6a54128fSAndroid Build Coastguard Worker 
95*6a54128fSAndroid Build Coastguard Worker 	p = line + strlen(line) - 1;
96*6a54128fSAndroid Build Coastguard Worker 
97*6a54128fSAndroid Build Coastguard Worker 	while (*line) {
98*6a54128fSAndroid Build Coastguard Worker 		if (isspace(*p))
99*6a54128fSAndroid Build Coastguard Worker 			*p-- = '\0';
100*6a54128fSAndroid Build Coastguard Worker 		else
101*6a54128fSAndroid Build Coastguard Worker 			break;
102*6a54128fSAndroid Build Coastguard Worker 	}
103*6a54128fSAndroid Build Coastguard Worker 
104*6a54128fSAndroid Build Coastguard Worker 	return line;
105*6a54128fSAndroid Build Coastguard Worker }
106*6a54128fSAndroid Build Coastguard Worker 
107*6a54128fSAndroid Build Coastguard Worker #if 0
108*6a54128fSAndroid Build Coastguard Worker static char *parse_word(char **buf)
109*6a54128fSAndroid Build Coastguard Worker {
110*6a54128fSAndroid Build Coastguard Worker 	char *word, *next;
111*6a54128fSAndroid Build Coastguard Worker 
112*6a54128fSAndroid Build Coastguard Worker 	word = *buf;
113*6a54128fSAndroid Build Coastguard Worker 	if (*word == '\0')
114*6a54128fSAndroid Build Coastguard Worker 		return NULL;
115*6a54128fSAndroid Build Coastguard Worker 
116*6a54128fSAndroid Build Coastguard Worker 	word = skip_over_blank(word);
117*6a54128fSAndroid Build Coastguard Worker 	next = skip_over_word(word);
118*6a54128fSAndroid Build Coastguard Worker 	if (*next) {
119*6a54128fSAndroid Build Coastguard Worker 		char *end = next - 1;
120*6a54128fSAndroid Build Coastguard Worker 		if (*end == '"' || *end == '\'')
121*6a54128fSAndroid Build Coastguard Worker 			*end = '\0';
122*6a54128fSAndroid Build Coastguard Worker 		*next++ = '\0';
123*6a54128fSAndroid Build Coastguard Worker 	}
124*6a54128fSAndroid Build Coastguard Worker 	*buf = next;
125*6a54128fSAndroid Build Coastguard Worker 
126*6a54128fSAndroid Build Coastguard Worker 	if (*word == '"' || *word == '\'')
127*6a54128fSAndroid Build Coastguard Worker 		word++;
128*6a54128fSAndroid Build Coastguard Worker 	return word;
129*6a54128fSAndroid Build Coastguard Worker }
130*6a54128fSAndroid Build Coastguard Worker #endif
131*6a54128fSAndroid Build Coastguard Worker 
132*6a54128fSAndroid Build Coastguard Worker /*
133*6a54128fSAndroid Build Coastguard Worker  * Start parsing a new line from the cache.
134*6a54128fSAndroid Build Coastguard Worker  *
135*6a54128fSAndroid Build Coastguard Worker  * line starts with "<device" return 1 -> continue parsing line
136*6a54128fSAndroid Build Coastguard Worker  * line starts with "<foo", empty, or # return 0 -> skip line
137*6a54128fSAndroid Build Coastguard Worker  * line starts with other, return -BLKID_ERR_CACHE -> error
138*6a54128fSAndroid Build Coastguard Worker  */
parse_start(char ** cp)139*6a54128fSAndroid Build Coastguard Worker static int parse_start(char **cp)
140*6a54128fSAndroid Build Coastguard Worker {
141*6a54128fSAndroid Build Coastguard Worker 	char *p;
142*6a54128fSAndroid Build Coastguard Worker 
143*6a54128fSAndroid Build Coastguard Worker 	p = strip_line(*cp);
144*6a54128fSAndroid Build Coastguard Worker 
145*6a54128fSAndroid Build Coastguard Worker 	/* Skip comment or blank lines.  We can't just NUL the first '#' char,
146*6a54128fSAndroid Build Coastguard Worker 	 * in case it is inside quotes, or escaped.
147*6a54128fSAndroid Build Coastguard Worker 	 */
148*6a54128fSAndroid Build Coastguard Worker 	if (*p == '\0' || *p == '#')
149*6a54128fSAndroid Build Coastguard Worker 		return 0;
150*6a54128fSAndroid Build Coastguard Worker 
151*6a54128fSAndroid Build Coastguard Worker 	if (!strncmp(p, "<device", 7)) {
152*6a54128fSAndroid Build Coastguard Worker 		DBG(DEBUG_READ, printf("found device header: %8s\n", p));
153*6a54128fSAndroid Build Coastguard Worker 		p += 7;
154*6a54128fSAndroid Build Coastguard Worker 
155*6a54128fSAndroid Build Coastguard Worker 		*cp = p;
156*6a54128fSAndroid Build Coastguard Worker 		return 1;
157*6a54128fSAndroid Build Coastguard Worker 	}
158*6a54128fSAndroid Build Coastguard Worker 
159*6a54128fSAndroid Build Coastguard Worker 	if (*p == '<')
160*6a54128fSAndroid Build Coastguard Worker 		return 0;
161*6a54128fSAndroid Build Coastguard Worker 
162*6a54128fSAndroid Build Coastguard Worker 	return -BLKID_ERR_CACHE;
163*6a54128fSAndroid Build Coastguard Worker }
164*6a54128fSAndroid Build Coastguard Worker 
165*6a54128fSAndroid Build Coastguard Worker /* Consume the remaining XML on the line (cosmetic only) */
parse_end(char ** cp)166*6a54128fSAndroid Build Coastguard Worker static int parse_end(char **cp)
167*6a54128fSAndroid Build Coastguard Worker {
168*6a54128fSAndroid Build Coastguard Worker 	*cp = skip_over_blank(*cp);
169*6a54128fSAndroid Build Coastguard Worker 
170*6a54128fSAndroid Build Coastguard Worker 	if (!strncmp(*cp, "</device>", 9)) {
171*6a54128fSAndroid Build Coastguard Worker 		DBG(DEBUG_READ, printf("found device trailer %9s\n", *cp));
172*6a54128fSAndroid Build Coastguard Worker 		*cp += 9;
173*6a54128fSAndroid Build Coastguard Worker 		return 0;
174*6a54128fSAndroid Build Coastguard Worker 	}
175*6a54128fSAndroid Build Coastguard Worker 
176*6a54128fSAndroid Build Coastguard Worker 	return -BLKID_ERR_CACHE;
177*6a54128fSAndroid Build Coastguard Worker }
178*6a54128fSAndroid Build Coastguard Worker 
179*6a54128fSAndroid Build Coastguard Worker /*
180*6a54128fSAndroid Build Coastguard Worker  * Allocate a new device struct with device name filled in.  Will handle
181*6a54128fSAndroid Build Coastguard Worker  * finding the device on lines of the form:
182*6a54128fSAndroid Build Coastguard Worker  * <device foo=bar>devname</device>
183*6a54128fSAndroid Build Coastguard Worker  * <device>devname<foo>bar</foo></device>
184*6a54128fSAndroid Build Coastguard Worker  */
parse_dev(blkid_cache cache,blkid_dev * dev,char ** cp)185*6a54128fSAndroid Build Coastguard Worker static int parse_dev(blkid_cache cache, blkid_dev *dev, char **cp)
186*6a54128fSAndroid Build Coastguard Worker {
187*6a54128fSAndroid Build Coastguard Worker 	char *start, *tmp, *end, *name;
188*6a54128fSAndroid Build Coastguard Worker 	int ret;
189*6a54128fSAndroid Build Coastguard Worker 
190*6a54128fSAndroid Build Coastguard Worker 	if ((ret = parse_start(cp)) <= 0)
191*6a54128fSAndroid Build Coastguard Worker 		return ret;
192*6a54128fSAndroid Build Coastguard Worker 
193*6a54128fSAndroid Build Coastguard Worker 	start = tmp = strchr(*cp, '>');
194*6a54128fSAndroid Build Coastguard Worker 	if (!start) {
195*6a54128fSAndroid Build Coastguard Worker 		DBG(DEBUG_READ,
196*6a54128fSAndroid Build Coastguard Worker 		    printf("blkid: short line parsing dev: %s\n", *cp));
197*6a54128fSAndroid Build Coastguard Worker 		return -BLKID_ERR_CACHE;
198*6a54128fSAndroid Build Coastguard Worker 	}
199*6a54128fSAndroid Build Coastguard Worker 	start = skip_over_blank(start + 1);
200*6a54128fSAndroid Build Coastguard Worker 	end = skip_over_word(start);
201*6a54128fSAndroid Build Coastguard Worker 
202*6a54128fSAndroid Build Coastguard Worker 	DBG(DEBUG_READ, printf("device should be %.*s\n",
203*6a54128fSAndroid Build Coastguard Worker 			       (int)(end - start), start));
204*6a54128fSAndroid Build Coastguard Worker 
205*6a54128fSAndroid Build Coastguard Worker 	if (**cp == '>')
206*6a54128fSAndroid Build Coastguard Worker 		*cp = end;
207*6a54128fSAndroid Build Coastguard Worker 	else
208*6a54128fSAndroid Build Coastguard Worker 		(*cp)++;
209*6a54128fSAndroid Build Coastguard Worker 
210*6a54128fSAndroid Build Coastguard Worker 	*tmp = '\0';
211*6a54128fSAndroid Build Coastguard Worker 
212*6a54128fSAndroid Build Coastguard Worker 	if (!(tmp = strrchr(end, '<')) || parse_end(&tmp) < 0) {
213*6a54128fSAndroid Build Coastguard Worker 		DBG(DEBUG_READ,
214*6a54128fSAndroid Build Coastguard Worker 		    printf("blkid: missing </device> ending: %s\n", end));
215*6a54128fSAndroid Build Coastguard Worker 	} else if (tmp)
216*6a54128fSAndroid Build Coastguard Worker 		*tmp = '\0';
217*6a54128fSAndroid Build Coastguard Worker 
218*6a54128fSAndroid Build Coastguard Worker 	if (end - start <= 1) {
219*6a54128fSAndroid Build Coastguard Worker 		DBG(DEBUG_READ, printf("blkid: empty device name: %s\n", *cp));
220*6a54128fSAndroid Build Coastguard Worker 		return -BLKID_ERR_CACHE;
221*6a54128fSAndroid Build Coastguard Worker 	}
222*6a54128fSAndroid Build Coastguard Worker 
223*6a54128fSAndroid Build Coastguard Worker 	name = blkid_strndup(start, end-start);
224*6a54128fSAndroid Build Coastguard Worker 	if (name == NULL)
225*6a54128fSAndroid Build Coastguard Worker 		return -BLKID_ERR_MEM;
226*6a54128fSAndroid Build Coastguard Worker 
227*6a54128fSAndroid Build Coastguard Worker 	DBG(DEBUG_READ, printf("found dev %s\n", name));
228*6a54128fSAndroid Build Coastguard Worker 
229*6a54128fSAndroid Build Coastguard Worker 	if (!(*dev = blkid_get_dev(cache, name, BLKID_DEV_CREATE))) {
230*6a54128fSAndroid Build Coastguard Worker 		free(name);
231*6a54128fSAndroid Build Coastguard Worker 		return -BLKID_ERR_MEM;
232*6a54128fSAndroid Build Coastguard Worker 	}
233*6a54128fSAndroid Build Coastguard Worker 
234*6a54128fSAndroid Build Coastguard Worker 	free(name);
235*6a54128fSAndroid Build Coastguard Worker 	return 1;
236*6a54128fSAndroid Build Coastguard Worker }
237*6a54128fSAndroid Build Coastguard Worker 
238*6a54128fSAndroid Build Coastguard Worker /*
239*6a54128fSAndroid Build Coastguard Worker  * Extract a tag of the form NAME="value" from the line.
240*6a54128fSAndroid Build Coastguard Worker  */
parse_token(char ** name,char ** value,char ** cp)241*6a54128fSAndroid Build Coastguard Worker static int parse_token(char **name, char **value, char **cp)
242*6a54128fSAndroid Build Coastguard Worker {
243*6a54128fSAndroid Build Coastguard Worker 	char *end;
244*6a54128fSAndroid Build Coastguard Worker 
245*6a54128fSAndroid Build Coastguard Worker 	if (!name || !value || !cp)
246*6a54128fSAndroid Build Coastguard Worker 		return -BLKID_ERR_PARAM;
247*6a54128fSAndroid Build Coastguard Worker 
248*6a54128fSAndroid Build Coastguard Worker 	if (!(*value = strchr(*cp, '=')))
249*6a54128fSAndroid Build Coastguard Worker 		return 0;
250*6a54128fSAndroid Build Coastguard Worker 
251*6a54128fSAndroid Build Coastguard Worker 	**value = '\0';
252*6a54128fSAndroid Build Coastguard Worker 	*name = strip_line(*cp);
253*6a54128fSAndroid Build Coastguard Worker 	*value = skip_over_blank(*value + 1);
254*6a54128fSAndroid Build Coastguard Worker 
255*6a54128fSAndroid Build Coastguard Worker 	if (**value == '"') {
256*6a54128fSAndroid Build Coastguard Worker 		end = strchr(*value + 1, '"');
257*6a54128fSAndroid Build Coastguard Worker 		if (!end) {
258*6a54128fSAndroid Build Coastguard Worker 			DBG(DEBUG_READ,
259*6a54128fSAndroid Build Coastguard Worker 			    printf("unbalanced quotes at: %s\n", *value));
260*6a54128fSAndroid Build Coastguard Worker 			*cp = *value;
261*6a54128fSAndroid Build Coastguard Worker 			return -BLKID_ERR_CACHE;
262*6a54128fSAndroid Build Coastguard Worker 		}
263*6a54128fSAndroid Build Coastguard Worker 		(*value)++;
264*6a54128fSAndroid Build Coastguard Worker 		*end = '\0';
265*6a54128fSAndroid Build Coastguard Worker 		end++;
266*6a54128fSAndroid Build Coastguard Worker 	} else {
267*6a54128fSAndroid Build Coastguard Worker 		end = skip_over_word(*value);
268*6a54128fSAndroid Build Coastguard Worker 		if (*end) {
269*6a54128fSAndroid Build Coastguard Worker 			*end = '\0';
270*6a54128fSAndroid Build Coastguard Worker 			end++;
271*6a54128fSAndroid Build Coastguard Worker 		}
272*6a54128fSAndroid Build Coastguard Worker 	}
273*6a54128fSAndroid Build Coastguard Worker 	*cp = end;
274*6a54128fSAndroid Build Coastguard Worker 
275*6a54128fSAndroid Build Coastguard Worker 	return 1;
276*6a54128fSAndroid Build Coastguard Worker }
277*6a54128fSAndroid Build Coastguard Worker 
278*6a54128fSAndroid Build Coastguard Worker /*
279*6a54128fSAndroid Build Coastguard Worker  * Extract a tag of the form <NAME>value</NAME> from the line.
280*6a54128fSAndroid Build Coastguard Worker  */
281*6a54128fSAndroid Build Coastguard Worker /*
282*6a54128fSAndroid Build Coastguard Worker static int parse_xml(char **name, char **value, char **cp)
283*6a54128fSAndroid Build Coastguard Worker {
284*6a54128fSAndroid Build Coastguard Worker 	char *end;
285*6a54128fSAndroid Build Coastguard Worker 
286*6a54128fSAndroid Build Coastguard Worker 	if (!name || !value || !cp)
287*6a54128fSAndroid Build Coastguard Worker 		return -BLKID_ERR_PARAM;
288*6a54128fSAndroid Build Coastguard Worker 
289*6a54128fSAndroid Build Coastguard Worker 	*name = strip_line(*cp);
290*6a54128fSAndroid Build Coastguard Worker 
291*6a54128fSAndroid Build Coastguard Worker 	if ((*name)[0] != '<' || (*name)[1] == '/')
292*6a54128fSAndroid Build Coastguard Worker 		return 0;
293*6a54128fSAndroid Build Coastguard Worker 
294*6a54128fSAndroid Build Coastguard Worker 	FIXME: finish this.
295*6a54128fSAndroid Build Coastguard Worker }
296*6a54128fSAndroid Build Coastguard Worker */
297*6a54128fSAndroid Build Coastguard Worker 
298*6a54128fSAndroid Build Coastguard Worker /*
299*6a54128fSAndroid Build Coastguard Worker  * Extract a tag from the line.
300*6a54128fSAndroid Build Coastguard Worker  *
301*6a54128fSAndroid Build Coastguard Worker  * Return 1 if a valid tag was found.
302*6a54128fSAndroid Build Coastguard Worker  * Return 0 if no tag found.
303*6a54128fSAndroid Build Coastguard Worker  * Return -ve error code.
304*6a54128fSAndroid Build Coastguard Worker  */
parse_tag(blkid_cache cache,blkid_dev dev,char ** cp)305*6a54128fSAndroid Build Coastguard Worker static int parse_tag(blkid_cache cache, blkid_dev dev, char **cp)
306*6a54128fSAndroid Build Coastguard Worker {
307*6a54128fSAndroid Build Coastguard Worker 	char *name;
308*6a54128fSAndroid Build Coastguard Worker 	char *value;
309*6a54128fSAndroid Build Coastguard Worker 	int ret;
310*6a54128fSAndroid Build Coastguard Worker 
311*6a54128fSAndroid Build Coastguard Worker 	if (!cache || !dev)
312*6a54128fSAndroid Build Coastguard Worker 		return -BLKID_ERR_PARAM;
313*6a54128fSAndroid Build Coastguard Worker 
314*6a54128fSAndroid Build Coastguard Worker 	if ((ret = parse_token(&name, &value, cp)) <= 0 /* &&
315*6a54128fSAndroid Build Coastguard Worker 	    (ret = parse_xml(&name, &value, cp)) <= 0 */)
316*6a54128fSAndroid Build Coastguard Worker 		return ret;
317*6a54128fSAndroid Build Coastguard Worker 
318*6a54128fSAndroid Build Coastguard Worker 	/* Some tags are stored directly in the device struct */
319*6a54128fSAndroid Build Coastguard Worker 	if (!strcmp(name, "DEVNO"))
320*6a54128fSAndroid Build Coastguard Worker 		dev->bid_devno = STRTOULL(value, 0, 0);
321*6a54128fSAndroid Build Coastguard Worker 	else if (!strcmp(name, "PRI"))
322*6a54128fSAndroid Build Coastguard Worker 		dev->bid_pri = strtol(value, 0, 0);
323*6a54128fSAndroid Build Coastguard Worker 	else if (!strcmp(name, "TIME"))
324*6a54128fSAndroid Build Coastguard Worker 		dev->bid_time = STRTOULL(value, 0, 0);
325*6a54128fSAndroid Build Coastguard Worker 	else
326*6a54128fSAndroid Build Coastguard Worker 		ret = blkid_set_tag(dev, name, value, strlen(value));
327*6a54128fSAndroid Build Coastguard Worker 
328*6a54128fSAndroid Build Coastguard Worker 	DBG(DEBUG_READ, printf("    tag: %s=\"%s\"\n", name, value));
329*6a54128fSAndroid Build Coastguard Worker 
330*6a54128fSAndroid Build Coastguard Worker 	return ret < 0 ? ret : 1;
331*6a54128fSAndroid Build Coastguard Worker }
332*6a54128fSAndroid Build Coastguard Worker 
333*6a54128fSAndroid Build Coastguard Worker /*
334*6a54128fSAndroid Build Coastguard Worker  * Parse a single line of data, and return a newly allocated dev struct.
335*6a54128fSAndroid Build Coastguard Worker  * Add the new device to the cache struct, if one was read.
336*6a54128fSAndroid Build Coastguard Worker  *
337*6a54128fSAndroid Build Coastguard Worker  * Lines are of the form <device [TAG="value" ...]>/dev/foo</device>
338*6a54128fSAndroid Build Coastguard Worker  *
339*6a54128fSAndroid Build Coastguard Worker  * Returns -ve value on error.
340*6a54128fSAndroid Build Coastguard Worker  * Returns 0 otherwise.
341*6a54128fSAndroid Build Coastguard Worker  * If a valid device was read, *dev_p is non-NULL, otherwise it is NULL
342*6a54128fSAndroid Build Coastguard Worker  * (e.g. comment lines, unknown XML content, etc).
343*6a54128fSAndroid Build Coastguard Worker  */
blkid_parse_line(blkid_cache cache,blkid_dev * dev_p,char * cp)344*6a54128fSAndroid Build Coastguard Worker static int blkid_parse_line(blkid_cache cache, blkid_dev *dev_p, char *cp)
345*6a54128fSAndroid Build Coastguard Worker {
346*6a54128fSAndroid Build Coastguard Worker 	blkid_dev dev;
347*6a54128fSAndroid Build Coastguard Worker 	int ret;
348*6a54128fSAndroid Build Coastguard Worker 
349*6a54128fSAndroid Build Coastguard Worker 	if (!cache || !dev_p)
350*6a54128fSAndroid Build Coastguard Worker 		return -BLKID_ERR_PARAM;
351*6a54128fSAndroid Build Coastguard Worker 
352*6a54128fSAndroid Build Coastguard Worker 	*dev_p = NULL;
353*6a54128fSAndroid Build Coastguard Worker 
354*6a54128fSAndroid Build Coastguard Worker 	DBG(DEBUG_READ, printf("line: %s\n", cp));
355*6a54128fSAndroid Build Coastguard Worker 
356*6a54128fSAndroid Build Coastguard Worker 	if ((ret = parse_dev(cache, dev_p, &cp)) <= 0)
357*6a54128fSAndroid Build Coastguard Worker 		return ret;
358*6a54128fSAndroid Build Coastguard Worker 
359*6a54128fSAndroid Build Coastguard Worker 	dev = *dev_p;
360*6a54128fSAndroid Build Coastguard Worker 
361*6a54128fSAndroid Build Coastguard Worker 	while ((ret = parse_tag(cache, dev, &cp)) > 0) {
362*6a54128fSAndroid Build Coastguard Worker 		;
363*6a54128fSAndroid Build Coastguard Worker 	}
364*6a54128fSAndroid Build Coastguard Worker 
365*6a54128fSAndroid Build Coastguard Worker 	if (dev->bid_type == NULL) {
366*6a54128fSAndroid Build Coastguard Worker 		DBG(DEBUG_READ,
367*6a54128fSAndroid Build Coastguard Worker 		    printf("blkid: device %s has no TYPE\n",dev->bid_name));
368*6a54128fSAndroid Build Coastguard Worker 		blkid_free_dev(dev);
369*6a54128fSAndroid Build Coastguard Worker 	}
370*6a54128fSAndroid Build Coastguard Worker 
371*6a54128fSAndroid Build Coastguard Worker 	DBG(DEBUG_READ, blkid_debug_dump_dev(dev));
372*6a54128fSAndroid Build Coastguard Worker 
373*6a54128fSAndroid Build Coastguard Worker 	return ret;
374*6a54128fSAndroid Build Coastguard Worker }
375*6a54128fSAndroid Build Coastguard Worker 
376*6a54128fSAndroid Build Coastguard Worker /*
377*6a54128fSAndroid Build Coastguard Worker  * Parse the specified filename, and return the data in the supplied or
378*6a54128fSAndroid Build Coastguard Worker  * a newly allocated cache struct.  If the file doesn't exist, return a
379*6a54128fSAndroid Build Coastguard Worker  * new empty cache struct.
380*6a54128fSAndroid Build Coastguard Worker  */
blkid_read_cache(blkid_cache cache)381*6a54128fSAndroid Build Coastguard Worker void blkid_read_cache(blkid_cache cache)
382*6a54128fSAndroid Build Coastguard Worker {
383*6a54128fSAndroid Build Coastguard Worker 	FILE *file;
384*6a54128fSAndroid Build Coastguard Worker 	char buf[4096];
385*6a54128fSAndroid Build Coastguard Worker 	int fd, lineno = 0;
386*6a54128fSAndroid Build Coastguard Worker 	struct stat st;
387*6a54128fSAndroid Build Coastguard Worker 
388*6a54128fSAndroid Build Coastguard Worker 	if (!cache)
389*6a54128fSAndroid Build Coastguard Worker 		return;
390*6a54128fSAndroid Build Coastguard Worker 
391*6a54128fSAndroid Build Coastguard Worker 	/*
392*6a54128fSAndroid Build Coastguard Worker 	 * If the file doesn't exist, then we just return an empty
393*6a54128fSAndroid Build Coastguard Worker 	 * struct so that the cache can be populated.
394*6a54128fSAndroid Build Coastguard Worker 	 */
395*6a54128fSAndroid Build Coastguard Worker 	if ((fd = open(cache->bic_filename, O_RDONLY)) < 0)
396*6a54128fSAndroid Build Coastguard Worker 		return;
397*6a54128fSAndroid Build Coastguard Worker 	if (fstat(fd, &st) < 0)
398*6a54128fSAndroid Build Coastguard Worker 		goto errout;
399*6a54128fSAndroid Build Coastguard Worker 	if ((st.st_mtime == cache->bic_ftime) ||
400*6a54128fSAndroid Build Coastguard Worker 	    (cache->bic_flags & BLKID_BIC_FL_CHANGED)) {
401*6a54128fSAndroid Build Coastguard Worker 		DBG(DEBUG_CACHE, printf("skipping re-read of %s\n",
402*6a54128fSAndroid Build Coastguard Worker 					cache->bic_filename));
403*6a54128fSAndroid Build Coastguard Worker 		goto errout;
404*6a54128fSAndroid Build Coastguard Worker 	}
405*6a54128fSAndroid Build Coastguard Worker 
406*6a54128fSAndroid Build Coastguard Worker 	DBG(DEBUG_CACHE, printf("reading cache file %s\n",
407*6a54128fSAndroid Build Coastguard Worker 				cache->bic_filename));
408*6a54128fSAndroid Build Coastguard Worker 
409*6a54128fSAndroid Build Coastguard Worker 	file = fdopen(fd, "r");
410*6a54128fSAndroid Build Coastguard Worker 	if (!file)
411*6a54128fSAndroid Build Coastguard Worker 		goto errout;
412*6a54128fSAndroid Build Coastguard Worker 
413*6a54128fSAndroid Build Coastguard Worker 	while (fgets(buf, sizeof(buf), file)) {
414*6a54128fSAndroid Build Coastguard Worker 		blkid_dev dev;
415*6a54128fSAndroid Build Coastguard Worker 		unsigned int end;
416*6a54128fSAndroid Build Coastguard Worker 
417*6a54128fSAndroid Build Coastguard Worker 		lineno++;
418*6a54128fSAndroid Build Coastguard Worker 		if (buf[0] == 0)
419*6a54128fSAndroid Build Coastguard Worker 			continue;
420*6a54128fSAndroid Build Coastguard Worker 		end = strlen(buf) - 1;
421*6a54128fSAndroid Build Coastguard Worker 		/* Continue reading next line if it ends with a backslash */
422*6a54128fSAndroid Build Coastguard Worker 		while (buf[end] == '\\' && end < sizeof(buf) - 2 &&
423*6a54128fSAndroid Build Coastguard Worker 		       fgets(buf + end, sizeof(buf) - end, file)) {
424*6a54128fSAndroid Build Coastguard Worker 			end = strlen(buf) - 1;
425*6a54128fSAndroid Build Coastguard Worker 			lineno++;
426*6a54128fSAndroid Build Coastguard Worker 		}
427*6a54128fSAndroid Build Coastguard Worker 
428*6a54128fSAndroid Build Coastguard Worker 		if (blkid_parse_line(cache, &dev, buf) < 0) {
429*6a54128fSAndroid Build Coastguard Worker 			DBG(DEBUG_READ,
430*6a54128fSAndroid Build Coastguard Worker 			    printf("blkid: bad format on line %d\n", lineno));
431*6a54128fSAndroid Build Coastguard Worker 			continue;
432*6a54128fSAndroid Build Coastguard Worker 		}
433*6a54128fSAndroid Build Coastguard Worker 	}
434*6a54128fSAndroid Build Coastguard Worker 	fclose(file);
435*6a54128fSAndroid Build Coastguard Worker 
436*6a54128fSAndroid Build Coastguard Worker 	/*
437*6a54128fSAndroid Build Coastguard Worker 	 * Initially we do not need to write out the cache file.
438*6a54128fSAndroid Build Coastguard Worker 	 */
439*6a54128fSAndroid Build Coastguard Worker 	cache->bic_flags &= ~BLKID_BIC_FL_CHANGED;
440*6a54128fSAndroid Build Coastguard Worker 	cache->bic_ftime = st.st_mtime;
441*6a54128fSAndroid Build Coastguard Worker 
442*6a54128fSAndroid Build Coastguard Worker 	return;
443*6a54128fSAndroid Build Coastguard Worker errout:
444*6a54128fSAndroid Build Coastguard Worker 	close(fd);
445*6a54128fSAndroid Build Coastguard Worker 	return;
446*6a54128fSAndroid Build Coastguard Worker }
447*6a54128fSAndroid Build Coastguard Worker 
448*6a54128fSAndroid Build Coastguard Worker #ifdef TEST_PROGRAM
debug_dump_dev(blkid_dev dev)449*6a54128fSAndroid Build Coastguard Worker static void debug_dump_dev(blkid_dev dev)
450*6a54128fSAndroid Build Coastguard Worker {
451*6a54128fSAndroid Build Coastguard Worker 	struct list_head *p;
452*6a54128fSAndroid Build Coastguard Worker 
453*6a54128fSAndroid Build Coastguard Worker 	if (!dev) {
454*6a54128fSAndroid Build Coastguard Worker 		printf("  dev: NULL\n");
455*6a54128fSAndroid Build Coastguard Worker 		return;
456*6a54128fSAndroid Build Coastguard Worker 	}
457*6a54128fSAndroid Build Coastguard Worker 
458*6a54128fSAndroid Build Coastguard Worker 	printf("  dev: name = %s\n", dev->bid_name);
459*6a54128fSAndroid Build Coastguard Worker 	printf("  dev: DEVNO=\"0x%0llx\"\n", (long long)dev->bid_devno);
460*6a54128fSAndroid Build Coastguard Worker 	printf("  dev: TIME=\"%lld\"\n", (long long)dev->bid_time);
461*6a54128fSAndroid Build Coastguard Worker 	printf("  dev: PRI=\"%d\"\n", dev->bid_pri);
462*6a54128fSAndroid Build Coastguard Worker 	printf("  dev: flags = 0x%08X\n", dev->bid_flags);
463*6a54128fSAndroid Build Coastguard Worker 
464*6a54128fSAndroid Build Coastguard Worker 	list_for_each(p, &dev->bid_tags) {
465*6a54128fSAndroid Build Coastguard Worker 		blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags);
466*6a54128fSAndroid Build Coastguard Worker 		if (tag)
467*6a54128fSAndroid Build Coastguard Worker 			printf("    tag: %s=\"%s\"\n", tag->bit_name,
468*6a54128fSAndroid Build Coastguard Worker 			       tag->bit_val);
469*6a54128fSAndroid Build Coastguard Worker 		else
470*6a54128fSAndroid Build Coastguard Worker 			printf("    tag: NULL\n");
471*6a54128fSAndroid Build Coastguard Worker 	}
472*6a54128fSAndroid Build Coastguard Worker 	printf("\n");
473*6a54128fSAndroid Build Coastguard Worker }
474*6a54128fSAndroid Build Coastguard Worker 
main(int argc,char ** argv)475*6a54128fSAndroid Build Coastguard Worker int main(int argc, char**argv)
476*6a54128fSAndroid Build Coastguard Worker {
477*6a54128fSAndroid Build Coastguard Worker 	blkid_cache cache = NULL;
478*6a54128fSAndroid Build Coastguard Worker 	int ret;
479*6a54128fSAndroid Build Coastguard Worker 
480*6a54128fSAndroid Build Coastguard Worker 	blkid_debug_mask = DEBUG_ALL;
481*6a54128fSAndroid Build Coastguard Worker 	if (argc > 2) {
482*6a54128fSAndroid Build Coastguard Worker 		fprintf(stderr, "Usage: %s [filename]\n"
483*6a54128fSAndroid Build Coastguard Worker 			"Test parsing of the cache (filename)\n", argv[0]);
484*6a54128fSAndroid Build Coastguard Worker 		exit(1);
485*6a54128fSAndroid Build Coastguard Worker 	}
486*6a54128fSAndroid Build Coastguard Worker 	if ((ret = blkid_get_cache(&cache, argv[1])) < 0)
487*6a54128fSAndroid Build Coastguard Worker 		fprintf(stderr, "error %d reading cache file %s\n", ret,
488*6a54128fSAndroid Build Coastguard Worker 			argv[1] ? argv[1] : BLKID_CACHE_FILE);
489*6a54128fSAndroid Build Coastguard Worker 
490*6a54128fSAndroid Build Coastguard Worker 	blkid_put_cache(cache);
491*6a54128fSAndroid Build Coastguard Worker 
492*6a54128fSAndroid Build Coastguard Worker 	return ret;
493*6a54128fSAndroid Build Coastguard Worker }
494*6a54128fSAndroid Build Coastguard Worker #endif
495