1e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o/*
2e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * read.c - read the blkid cache from disk, to avoid scanning all devices
3e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o *
450b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o * Copyright (C) 2001, 2003 Theodore Y. Ts'o
5e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * Copyright (C) 2001 Andreas Dilger
6e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o *
7e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * %Begin-Header%
8e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * This file may be redistributed under the terms of the
9e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * GNU Lesser General Public License.
10e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * %End-Header%
11e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o */
12e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
13864b8d4eab6a8b38fa9f89ac1475ad364f5a40b8Andreas Dilger#define _XOPEN_SOURCE 600 /* for inclusion of strtoull */
14864b8d4eab6a8b38fa9f89ac1475ad364f5a40b8Andreas Dilger
15e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#include <stdio.h>
16e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#include <ctype.h>
17e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#include <string.h>
18e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#include <time.h>
1979dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o#include <sys/types.h>
20e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#include <sys/stat.h>
2179dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o#include <fcntl.h>
22e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#include <unistd.h>
23e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#if HAVE_ERRNO_H
24e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#include <errno.h>
25e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#endif
26e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
277a603aa89fcffb8798eca34ca3858db6f0393046Theodore Ts'o#include "blkidP.h"
28e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#include "uuid/uuid.h"
29e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
30e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#ifdef HAVE_STRTOULL
31e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#define STRTOULL strtoull /* defined in stdlib.h if you try hard enough */
32e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#else
33e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o/* FIXME: need to support real strtoull here */
34e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#define STRTOULL strtoul
35e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#endif
36e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
37e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#if HAVE_STDLIB_H
38e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#include <stdlib.h>
39e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#endif
40e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
4155080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o#ifdef TEST_PROGRAM
4255080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o#define blkid_debug_dump_dev(dev)	(debug_dump_dev(dev))
4355080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'ostatic void debug_dump_dev(blkid_dev dev);
4455080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o#endif
4555080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o
46e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o/*
47e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * File format:
48e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o *
49e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o *	<device [<NAME="value"> ...]>device_name</device>
50e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o *
51e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o *	The following tags are required for each entry:
52e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o *	<ID="id">	unique (within this file) ID number of this device
53e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o *	<TIME="time">	(ascii time_t) time this entry was last read from disk
54e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o *	<TYPE="type">	(detected) type of filesystem/data for this partition
55e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o *
56e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o *	The following tags may be present, depending on the device contents
57e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o *	<LABEL="label">	(user supplied) label (volume name, etc)
58e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o *	<UUID="uuid">	(generated) universally unique identifier (serial no)
59e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o */
60e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
61e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'ostatic char *skip_over_blank(char *cp)
62e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o{
63e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	while (*cp && isspace(*cp))
64e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		cp++;
65e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	return cp;
66e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o}
67e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
68e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'ostatic char *skip_over_word(char *cp)
69e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o{
70e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	char ch;
71e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
72e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	while ((ch = *cp)) {
73e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		/* If we see a backslash, skip the next character */
74e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		if (ch == '\\') {
75e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o			cp++;
76e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o			if (*cp == '\0')
77e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o				break;
78e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o			cp++;
79e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o			continue;
80e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		}
81e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		if (isspace(ch) || ch == '<' || ch == '>')
82e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o			break;
83e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		cp++;
84e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	}
85e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	return cp;
86e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o}
87e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
88e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'ostatic char *strip_line(char *line)
89e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o{
90e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	char	*p;
91e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
92e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	line = skip_over_blank(line);
93e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
94e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	p = line + strlen(line) - 1;
95e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
96e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	while (*line) {
97e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		if (isspace(*p))
98e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o			*p-- = '\0';
99e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		else
100e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o			break;
101e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	}
102e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
103e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	return line;
104e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o}
105e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
106e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#if 0
107e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'ostatic char *parse_word(char **buf)
108e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o{
109e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	char *word, *next;
110e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
111e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	word = *buf;
112e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	if (*word == '\0')
113e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		return NULL;
114e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
115e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	word = skip_over_blank(word);
116e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	next = skip_over_word(word);
117e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	if (*next) {
118e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		char *end = next - 1;
119e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		if (*end == '"' || *end == '\'')
120e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o			*end = '\0';
121e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		*next++ = '\0';
122e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	}
123e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	*buf = next;
124e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
125e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	if (*word == '"' || *word == '\'')
126e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		word++;
127e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	return word;
128e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o}
129e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#endif
130e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
131e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o/*
132e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * Start parsing a new line from the cache.
133e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o *
134e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * line starts with "<device" return 1 -> continue parsing line
135e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * line starts with "<foo", empty, or # return 0 -> skip line
136e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * line starts with other, return -BLKID_ERR_CACHE -> error
137e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o */
138e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'ostatic int parse_start(char **cp)
139e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o{
140e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	char *p;
141e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
142e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	p = strip_line(*cp);
143e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
144e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	/* Skip comment or blank lines.  We can't just NUL the first '#' char,
145e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	 * in case it is inside quotes, or escaped.
146e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	 */
147e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	if (*p == '\0' || *p == '#')
148e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		return 0;
149e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
150e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	if (!strncmp(p, "<device", 7)) {
151f0a22d0fd3ec3f45b562af5afba8811f72b94a28Theodore Ts'o		DBG(DEBUG_READ, printf("found device header: %8s\n", p));
152e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		p += 7;
153e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
154e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		*cp = p;
155e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		return 1;
156e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	}
157e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
158e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	if (*p == '<')
159e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		return 0;
160e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
161e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	return -BLKID_ERR_CACHE;
162e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o}
163e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
164e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o/* Consume the remaining XML on the line (cosmetic only) */
165e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'ostatic int parse_end(char **cp)
166e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o{
167e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	*cp = skip_over_blank(*cp);
168e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
169e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	if (!strncmp(*cp, "</device>", 9)) {
170f0a22d0fd3ec3f45b562af5afba8811f72b94a28Theodore Ts'o		DBG(DEBUG_READ, printf("found device trailer %9s\n", *cp));
171e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		*cp += 9;
172e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		return 0;
173e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	}
174e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
175e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	return -BLKID_ERR_CACHE;
176e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o}
177e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
178e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o/*
179e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * Allocate a new device struct with device name filled in.  Will handle
180e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * finding the device on lines of the form:
181e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * <device foo=bar>devname</device>
182e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * <device>devname<foo>bar</foo></device>
183e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o */
18450b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'ostatic int parse_dev(blkid_cache cache, blkid_dev *dev, char **cp)
185e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o{
18650b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o	char *start, *tmp, *end, *name;
187e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	int ret;
188e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
189e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	if ((ret = parse_start(cp)) <= 0)
190e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		return ret;
191e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
192e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	start = tmp = strchr(*cp, '>');
193e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	if (!start) {
194f0a22d0fd3ec3f45b562af5afba8811f72b94a28Theodore Ts'o		DBG(DEBUG_READ,
195f0a22d0fd3ec3f45b562af5afba8811f72b94a28Theodore Ts'o		    printf("blkid: short line parsing dev: %s\n", *cp));
196e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		return -BLKID_ERR_CACHE;
197e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	}
198e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	start = skip_over_blank(start + 1);
199e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	end = skip_over_word(start);
200e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
201de8f3a76218255e443ba57dec5d74850180fa75dAndreas Dilger	DBG(DEBUG_READ, printf("device should be %*s\n",
202de8f3a76218255e443ba57dec5d74850180fa75dAndreas Dilger			       (int)(end - start), start));
203e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
204e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	if (**cp == '>')
205e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		*cp = end;
206e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	else
207e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		(*cp)++;
208e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
209e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	*tmp = '\0';
210e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
211f0a22d0fd3ec3f45b562af5afba8811f72b94a28Theodore Ts'o	if (!(tmp = strrchr(end, '<')) || parse_end(&tmp) < 0) {
212f0a22d0fd3ec3f45b562af5afba8811f72b94a28Theodore Ts'o		DBG(DEBUG_READ,
213f0a22d0fd3ec3f45b562af5afba8811f72b94a28Theodore Ts'o		    printf("blkid: missing </device> ending: %s\n", end));
214f0a22d0fd3ec3f45b562af5afba8811f72b94a28Theodore Ts'o	} else if (tmp)
215e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		*tmp = '\0';
216e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
217e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	if (end - start <= 1) {
218f0a22d0fd3ec3f45b562af5afba8811f72b94a28Theodore Ts'o		DBG(DEBUG_READ, printf("blkid: empty device name: %s\n", *cp));
219e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		return -BLKID_ERR_CACHE;
220e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	}
221e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
22250b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o	name = blkid_strndup(start, end-start);
22350b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o	if (name == NULL)
224e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		return -BLKID_ERR_MEM;
225e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
226f0a22d0fd3ec3f45b562af5afba8811f72b94a28Theodore Ts'o	DBG(DEBUG_READ, printf("found dev %s\n", name));
227e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
228e0a700d45d4d5f85ddedc2344f336e9bb73a8b29Brian Behlendorf	if (!(*dev = blkid_get_dev(cache, name, BLKID_DEV_CREATE))) {
229e0a700d45d4d5f85ddedc2344f336e9bb73a8b29Brian Behlendorf		free(name);
23050b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o		return -BLKID_ERR_MEM;
231e0a700d45d4d5f85ddedc2344f336e9bb73a8b29Brian Behlendorf	}
232e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
23350b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o	free(name);
234e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	return 1;
235e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o}
236e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
237e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o/*
238e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * Extract a tag of the form NAME="value" from the line.
239e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o */
240e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'ostatic int parse_token(char **name, char **value, char **cp)
241e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o{
242e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	char *end;
243e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
244e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	if (!name || !value || !cp)
245e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		return -BLKID_ERR_PARAM;
246e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
247e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	if (!(*value = strchr(*cp, '=')))
248e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		return 0;
249e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
250e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	**value = '\0';
251e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	*name = strip_line(*cp);
252e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	*value = skip_over_blank(*value + 1);
253e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
254e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	if (**value == '"') {
255e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		end = strchr(*value + 1, '"');
256e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		if (!end) {
257f0a22d0fd3ec3f45b562af5afba8811f72b94a28Theodore Ts'o			DBG(DEBUG_READ,
258f0a22d0fd3ec3f45b562af5afba8811f72b94a28Theodore Ts'o			    printf("unbalanced quotes at: %s\n", *value));
259e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o			*cp = *value;
260e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o			return -BLKID_ERR_CACHE;
261e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		}
262e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		(*value)++;
263e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		*end = '\0';
264e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		end++;
265e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	} else {
266e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		end = skip_over_word(*value);
267e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		if (*end) {
268e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o			*end = '\0';
269e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o			end++;
270e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		}
271e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	}
272e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	*cp = end;
273e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
274e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	return 1;
275e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o}
276e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
277e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o/*
278e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * Extract a tag of the form <NAME>value</NAME> from the line.
279e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o */
280e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o/*
281e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'ostatic int parse_xml(char **name, char **value, char **cp)
282e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o{
283e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	char *end;
284e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
285e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	if (!name || !value || !cp)
286e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		return -BLKID_ERR_PARAM;
287e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
288e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	*name = strip_line(*cp);
289e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
290e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	if ((*name)[0] != '<' || (*name)[1] == '/')
291e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		return 0;
292e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
293e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	FIXME: finish this.
294e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o}
295e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o*/
296e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
297e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o/*
298e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * Extract a tag from the line.
299e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o *
300e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * Return 1 if a valid tag was found.
301e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * Return 0 if no tag found.
302e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * Return -ve error code.
303e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o */
30476b07bb1bc9cbcb70a94cb235954eaac993920adTheodore Ts'ostatic int parse_tag(blkid_cache cache, blkid_dev dev, char **cp)
305e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o{
306e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	char *name;
307e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	char *value;
308e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	int ret;
309e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
310e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	if (!cache || !dev)
311e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		return -BLKID_ERR_PARAM;
312e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
313e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	if ((ret = parse_token(&name, &value, cp)) <= 0 /* &&
314e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	    (ret = parse_xml(&name, &value, cp)) <= 0 */)
315e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		return ret;
316e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
317e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	/* Some tags are stored directly in the device struct */
318efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	if (!strcmp(name, "DEVNO"))
319e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		dev->bid_devno = STRTOULL(value, 0, 0);
320ce72b862c59da24ba16b354d687549276a24f908Theodore Ts'o	else if (!strcmp(name, "PRI"))
321ce72b862c59da24ba16b354d687549276a24f908Theodore Ts'o		dev->bid_pri = strtol(value, 0, 0);
322e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	else if (!strcmp(name, "TIME"))
323864b8d4eab6a8b38fa9f89ac1475ad364f5a40b8Andreas Dilger		dev->bid_time = STRTOULL(value, 0, 0);
324e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	else
32579dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o		ret = blkid_set_tag(dev, name, value, strlen(value));
32676b07bb1bc9cbcb70a94cb235954eaac993920adTheodore Ts'o
327f0a22d0fd3ec3f45b562af5afba8811f72b94a28Theodore Ts'o	DBG(DEBUG_READ, printf("    tag: %s=\"%s\"\n", name, value));
328e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
329e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	return ret < 0 ? ret : 1;
330e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o}
331e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
332e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o/*
333e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * Parse a single line of data, and return a newly allocated dev struct.
334e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * Add the new device to the cache struct, if one was read.
335e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o *
336e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * Lines are of the form <device [TAG="value" ...]>/dev/foo</device>
337e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o *
338e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * Returns -ve value on error.
339e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * Returns 0 otherwise.
340e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * If a valid device was read, *dev_p is non-NULL, otherwise it is NULL
341e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o * (e.g. comment lines, unknown XML content, etc).
342e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o */
3437a603aa89fcffb8798eca34ca3858db6f0393046Theodore Ts'ostatic int blkid_parse_line(blkid_cache cache, blkid_dev *dev_p, char *cp)
344e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o{
3457a603aa89fcffb8798eca34ca3858db6f0393046Theodore Ts'o	blkid_dev dev;
346e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	int ret;
347e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
348e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	if (!cache || !dev_p)
349e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		return -BLKID_ERR_PARAM;
350e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
351e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	*dev_p = NULL;
352e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
353f0a22d0fd3ec3f45b562af5afba8811f72b94a28Theodore Ts'o	DBG(DEBUG_READ, printf("line: %s\n", cp));
354e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
35550b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o	if ((ret = parse_dev(cache, dev_p, &cp)) <= 0)
356e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		return ret;
357e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
358e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	dev = *dev_p;
359e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
36076b07bb1bc9cbcb70a94cb235954eaac993920adTheodore Ts'o	while ((ret = parse_tag(cache, dev, &cp)) > 0) {
36176b07bb1bc9cbcb70a94cb235954eaac993920adTheodore Ts'o		;
362e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	}
363e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
364e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	if (dev->bid_type == NULL) {
365f0a22d0fd3ec3f45b562af5afba8811f72b94a28Theodore Ts'o		DBG(DEBUG_READ,
366f0a22d0fd3ec3f45b562af5afba8811f72b94a28Theodore Ts'o		    printf("blkid: device %s has no TYPE\n",dev->bid_name));
367e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		blkid_free_dev(dev);
368e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	}
369e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
37078c7d0efae91cde1a992f69c1a0157b39e971670Theodore Ts'o	DBG(DEBUG_READ, blkid_debug_dump_dev(dev));
371e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
372e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	return ret;
373e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o}
374e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
375e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o/*
37650b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o * Parse the specified filename, and return the data in the supplied or
37750b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o * a newly allocated cache struct.  If the file doesn't exist, return a
37850b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o * new empty cache struct.
379e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o */
38079dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'ovoid blkid_read_cache(blkid_cache cache)
381e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o{
38250b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o	FILE *file;
383e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	char buf[4096];
38479dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o	int fd, lineno = 0;
38579dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o	struct stat st;
386e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
38750b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o	if (!cache)
38879dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o		return;
389e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
39079dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o	/*
39179dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o	 * If the file doesn't exist, then we just return an empty
39279dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o	 * struct so that the cache can be populated.
39379dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o	 */
39479dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o	if ((fd = open(cache->bic_filename, O_RDONLY)) < 0)
395ed1b33e8fb310641684d68a177c940b58f2f529dTheodore Ts'o		return;
39679dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o	if (fstat(fd, &st) < 0)
39779dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o		goto errout;
39879dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o	if ((st.st_mtime == cache->bic_ftime) ||
39979dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o	    (cache->bic_flags & BLKID_BIC_FL_CHANGED)) {
40079dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o		DBG(DEBUG_CACHE, printf("skipping re-read of %s\n",
40179dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o					cache->bic_filename));
40279dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o		goto errout;
40350b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o	}
404efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
40579dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o	DBG(DEBUG_CACHE, printf("reading cache file %s\n",
40679dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o				cache->bic_filename));
40779dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o
40879dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o	file = fdopen(fd, "r");
40979dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o	if (!file)
41079dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o		goto errout;
41150b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o
412e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	while (fgets(buf, sizeof(buf), file)) {
4137a603aa89fcffb8798eca34ca3858db6f0393046Theodore Ts'o		blkid_dev dev;
414544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		unsigned int end;
415e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
416e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		lineno++;
417544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		if (buf[0] == 0)
418544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			continue;
419544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		end = strlen(buf) - 1;
420e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		/* Continue reading next line if it ends with a backslash */
421e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		while (buf[end] == '\\' && end < sizeof(buf) - 2 &&
42279dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o		       fgets(buf + end, sizeof(buf) - end, file)) {
423e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o			end = strlen(buf) - 1;
424e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o			lineno++;
425e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		}
426e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
42779dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o		if (blkid_parse_line(cache, &dev, buf) < 0) {
428f0a22d0fd3ec3f45b562af5afba8811f72b94a28Theodore Ts'o			DBG(DEBUG_READ,
429f0a22d0fd3ec3f45b562af5afba8811f72b94a28Theodore Ts'o			    printf("blkid: bad format on line %d\n", lineno));
430e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o			continue;
431e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		}
432e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	}
4331b510f57f4f0bf52b59a6e745894e202a9addb97Theodore Ts'o	fclose(file);
4341b510f57f4f0bf52b59a6e745894e202a9addb97Theodore Ts'o
435e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	/*
43650b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o	 * Initially we do not need to write out the cache file.
437e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	 */
43879dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o	cache->bic_flags &= ~BLKID_BIC_FL_CHANGED;
43979dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o	cache->bic_ftime = st.st_mtime;
440e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
441ed1b33e8fb310641684d68a177c940b58f2f529dTheodore Ts'o	return;
44279dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'oerrout:
44379dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o	close(fd);
44479dd234a799434b6dc8365c49e743f00eb09d2fdTheodore Ts'o	return;
445e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o}
446e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
447e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#ifdef TEST_PROGRAM
44855080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'ostatic void debug_dump_dev(blkid_dev dev)
44955080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o{
45055080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o	struct list_head *p;
45155080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o
45255080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o	if (!dev) {
45355080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o		printf("  dev: NULL\n");
45455080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o		return;
45555080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o	}
45655080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o
45755080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o	printf("  dev: name = %s\n", dev->bid_name);
45812a829dcdc57fb8ddc4887b07b40136288b6e7feMatthias Andree	printf("  dev: DEVNO=\"0x%0llx\"\n", (long long)dev->bid_devno);
45912a829dcdc57fb8ddc4887b07b40136288b6e7feMatthias Andree	printf("  dev: TIME=\"%lld\"\n", (long long)dev->bid_time);
46055080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o	printf("  dev: PRI=\"%d\"\n", dev->bid_pri);
46155080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o	printf("  dev: flags = 0x%08X\n", dev->bid_flags);
46255080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o
46355080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o	list_for_each(p, &dev->bid_tags) {
46455080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o		blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags);
46555080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o		if (tag)
466efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o			printf("    tag: %s=\"%s\"\n", tag->bit_name,
46755080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o			       tag->bit_val);
46855080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o		else
46955080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o			printf("    tag: NULL\n");
47055080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o	}
47155080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o	printf("\n");
47255080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o}
47355080a7637172402c51eb4f2fb2b81870c04de3dTheodore Ts'o
474e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'oint main(int argc, char**argv)
475e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o{
4767a603aa89fcffb8798eca34ca3858db6f0393046Theodore Ts'o	blkid_cache cache = NULL;
477e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	int ret;
478e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
479f0a22d0fd3ec3f45b562af5afba8811f72b94a28Theodore Ts'o	blkid_debug_mask = DEBUG_ALL;
480e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	if (argc > 2) {
481e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		fprintf(stderr, "Usage: %s [filename]\n"
482e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o			"Test parsing of the cache (filename)\n", argv[0]);
483e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		exit(1);
484e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	}
48550b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o	if ((ret = blkid_get_cache(&cache, argv[1])) < 0)
486e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o		fprintf(stderr, "error %d reading cache file %s\n", ret,
487e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o			argv[1] ? argv[1] : BLKID_CACHE_FILE);
488e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
48950b380b4d4ab668bad45033e3a8aaf93c7f42844Theodore Ts'o	blkid_put_cache(cache);
490e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o
491e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o	return ret;
492e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o}
493e12f2ae74c2eb8997bf13adf8fdd7e7313971eaeTheodore Ts'o#endif
494