* %End-Header%
*/
+#define _XOPEN_SOURCE 600 /* for inclusion of strtoull */
+
+#include "config.h"
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
+#include <sys/types.h>
#include <sys/stat.h>
+#include <fcntl.h>
#include <unistd.h>
#if HAVE_ERRNO_H
#include <errno.h>
#include "blkidP.h"
#include "uuid/uuid.h"
-#ifdef DEBUG_CACHE
-#define DBG(x) x
-#else
-#define DBG(x)
-#endif
-
#ifdef HAVE_STRTOULL
-#define __USE_ISOC9X
#define STRTOULL strtoull /* defined in stdlib.h if you try hard enough */
#else
/* FIXME: need to support real strtoull here */
#include <stdlib.h>
#endif
+#ifdef TEST_PROGRAM
+#define blkid_debug_dump_dev(dev) (debug_dump_dev(dev))
+static void debug_dump_dev(blkid_dev dev);
+#endif
+
/*
* File format:
*
return 0;
if (!strncmp(p, "<device", 7)) {
- DBG(printf("found device header: %8s\n", p));
+ DBG(DEBUG_READ, printf("found device header: %8s\n", p));
p += 7;
*cp = p;
*cp = skip_over_blank(*cp);
if (!strncmp(*cp, "</device>", 9)) {
- DBG(printf("found device trailer %9s\n", *cp));
+ DBG(DEBUG_READ, printf("found device trailer %9s\n", *cp));
*cp += 9;
return 0;
}
start = tmp = strchr(*cp, '>');
if (!start) {
- DBG(printf("blkid: short line parsing dev: %s\n", *cp));
+ DBG(DEBUG_READ,
+ printf("blkid: short line parsing dev: %s\n", *cp));
return -BLKID_ERR_CACHE;
}
start = skip_over_blank(start + 1);
end = skip_over_word(start);
- DBG(printf("device should be %*s\n", end - start, start));
+ DBG(DEBUG_READ, printf("device should be %*s\n",
+ (int)(end - start), start));
if (**cp == '>')
*cp = end;
*tmp = '\0';
- if (!(tmp = strrchr(end, '<')) || parse_end(&tmp) < 0)
- DBG(printf("blkid: missing </device> ending: %s\n", end));
- else if (tmp)
+ if (!(tmp = strrchr(end, '<')) || parse_end(&tmp) < 0) {
+ DBG(DEBUG_READ,
+ printf("blkid: missing </device> ending: %s\n", end));
+ } else if (tmp)
*tmp = '\0';
if (end - start <= 1) {
- DBG(printf("blkid: empty device name: %s\n", *cp));
+ DBG(DEBUG_READ, printf("blkid: empty device name: %s\n", *cp));
return -BLKID_ERR_CACHE;
}
if (name == NULL)
return -BLKID_ERR_MEM;
- DBG(printf("found dev %s\n", name));
+ DBG(DEBUG_READ, printf("found dev %s\n", name));
- if (!(*dev = blkid_get_dev(cache, name, BLKID_DEV_CREATE)))
+ if (!(*dev = blkid_get_dev(cache, name, BLKID_DEV_CREATE))) {
+ free(name);
return -BLKID_ERR_MEM;
+ }
free(name);
return 1;
if (**value == '"') {
end = strchr(*value + 1, '"');
if (!end) {
- DBG(printf("unbalanced quotes at: %s\n", *value));
+ DBG(DEBUG_READ,
+ printf("unbalanced quotes at: %s\n", *value));
*cp = *value;
return -BLKID_ERR_CACHE;
}
return ret;
/* Some tags are stored directly in the device struct */
- if (!strcmp(name, "DEVNO"))
+ if (!strcmp(name, "DEVNO"))
dev->bid_devno = STRTOULL(value, 0, 0);
else if (!strcmp(name, "PRI"))
dev->bid_pri = strtol(value, 0, 0);
else if (!strcmp(name, "TIME"))
- /* FIXME: need to parse a long long eventually */
- dev->bid_time = strtol(value, 0, 0);
+ dev->bid_time = STRTOULL(value, 0, 0);
else
- ret = blkid_set_tag(dev, name, value, strlen(value), 0);
+ ret = blkid_set_tag(dev, name, value, strlen(value));
- DBG(printf(" tag: %s=\"%s\"\n", name, value));
+ DBG(DEBUG_READ, printf(" tag: %s=\"%s\"\n", name, value));
return ret < 0 ? ret : 1;
}
*dev_p = NULL;
- DBG(printf("line: %s\n", cp));
+ DBG(DEBUG_READ, printf("line: %s\n", cp));
if ((ret = parse_dev(cache, dev_p, &cp)) <= 0)
return ret;
}
if (dev->bid_type == NULL) {
- DBG(printf("blkid: device %s has no TYPE\n",dev->bid_name));
+ DBG(DEBUG_READ,
+ printf("blkid: device %s has no TYPE\n",dev->bid_name));
blkid_free_dev(dev);
}
- DEB_DUMP_DEV(dev);
+ DBG(DEBUG_READ, blkid_debug_dump_dev(dev));
return ret;
}
* a newly allocated cache struct. If the file doesn't exist, return a
* new empty cache struct.
*/
-int blkid_get_cache(blkid_cache *cache, const char *filename)
+void blkid_read_cache(blkid_cache cache)
{
FILE *file;
char buf[4096];
- int lineno = 0;
+ int fd, lineno = 0;
+ struct stat st;
if (!cache)
- return -BLKID_ERR_PARAM;
-
- if ((*cache = blkid_new_cache()) == NULL)
- return -BLKID_ERR_MEM;
+ return;
- if (!filename || !strlen(filename))
- filename = BLKID_CACHE_FILE;
- else
- (*cache)->bic_filename = blkid_strdup(filename);
-
- DBG(printf("cache file %s\n", filename));
-
- if (!strcmp(filename, "-"))
- file = stdin;
- else {
- /*
- * If the file doesn't exist, then we just return an empty
- * struct so that the cache can be populated.
- */
- if (access(filename, R_OK) < 0)
- return 0;
-
- file = fopen(filename, "r");
- if (!file)
- return errno; /* Should never happen */
+ /*
+ * If the file doesn't exist, then we just return an empty
+ * struct so that the cache can be populated.
+ */
+ if ((fd = open(cache->bic_filename, O_RDONLY)) < 0)
+ return;
+ if (fstat(fd, &st) < 0)
+ goto errout;
+ if ((st.st_mtime == cache->bic_ftime) ||
+ (cache->bic_flags & BLKID_BIC_FL_CHANGED)) {
+ DBG(DEBUG_CACHE, printf("skipping re-read of %s\n",
+ cache->bic_filename));
+ goto errout;
}
+ DBG(DEBUG_CACHE, printf("reading cache file %s\n",
+ cache->bic_filename));
+
+ file = fdopen(fd, "r");
+ if (!file)
+ goto errout;
+
while (fgets(buf, sizeof(buf), file)) {
blkid_dev dev;
-
- int end = strlen(buf) - 1;
+ unsigned int end;
lineno++;
+ if (buf[0] == 0)
+ continue;
+ end = strlen(buf) - 1;
/* Continue reading next line if it ends with a backslash */
while (buf[end] == '\\' && end < sizeof(buf) - 2 &&
- fgets(buf + end, sizeof(buf) - end, stdin)) {
+ fgets(buf + end, sizeof(buf) - end, file)) {
end = strlen(buf) - 1;
lineno++;
}
- if (blkid_parse_line(*cache, &dev, buf) < 0) {
- DBG(printf("blkid: bad format on line %d\n", lineno));
+ if (blkid_parse_line(cache, &dev, buf) < 0) {
+ DBG(DEBUG_READ,
+ printf("blkid: bad format on line %d\n", lineno));
continue;
}
}
+ fclose(file);
+
/*
* Initially we do not need to write out the cache file.
*/
- (*cache)->bic_flags &= ~BLKID_BIC_FL_CHANGED;
-
- if (file != stdin)
- fclose(file);
+ cache->bic_flags &= ~BLKID_BIC_FL_CHANGED;
+ cache->bic_ftime = st.st_mtime;
- return 0;
+ return;
+errout:
+ close(fd);
+ return;
}
#ifdef TEST_PROGRAM
+static void debug_dump_dev(blkid_dev dev)
+{
+ struct list_head *p;
+
+ if (!dev) {
+ printf(" dev: NULL\n");
+ return;
+ }
+
+ printf(" dev: name = %s\n", dev->bid_name);
+ printf(" dev: DEVNO=\"0x%0llx\"\n", (long long)dev->bid_devno);
+ printf(" dev: TIME=\"%lld\"\n", (long long)dev->bid_time);
+ printf(" dev: PRI=\"%d\"\n", dev->bid_pri);
+ printf(" dev: flags = 0x%08X\n", dev->bid_flags);
+
+ list_for_each(p, &dev->bid_tags) {
+ blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags);
+ if (tag)
+ printf(" tag: %s=\"%s\"\n", tag->bit_name,
+ tag->bit_val);
+ else
+ printf(" tag: NULL\n");
+ }
+ printf("\n");
+}
+
int main(int argc, char**argv)
{
blkid_cache cache = NULL;
int ret;
+ blkid_debug_mask = DEBUG_ALL;
if (argc > 2) {
fprintf(stderr, "Usage: %s [filename]\n"
"Test parsing of the cache (filename)\n", argv[0]);