Whamcloud - gitweb
build: fix compile warnings on OSX
[tools/e2fsprogs.git] / lib / blkid / read.c
index 9d09b68..efc348b 100644 (file)
  * %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:
  *
@@ -146,7 +149,7 @@ static int parse_start(char **cp)
                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;
@@ -165,7 +168,7 @@ static int parse_end(char **cp)
        *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;
        }
@@ -189,13 +192,15 @@ static int parse_dev(blkid_cache cache, blkid_dev *dev, char **cp)
 
        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;
@@ -204,13 +209,14 @@ static int parse_dev(blkid_cache cache, blkid_dev *dev, char **cp)
 
        *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;
        }
 
@@ -218,10 +224,12 @@ static int parse_dev(blkid_cache cache, blkid_dev *dev, char **cp)
        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;
@@ -247,7 +255,8 @@ static int parse_token(char **name, char **value, char **cp)
        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;
                }
@@ -307,17 +316,16 @@ static int parse_tag(blkid_cache cache, blkid_dev dev, char **cp)
                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;
 }
@@ -343,7 +351,7 @@ static int blkid_parse_line(blkid_cache cache, blkid_dev *dev_p, char *cp)
 
        *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;
@@ -355,11 +363,12 @@ static int blkid_parse_line(blkid_cache cache, blkid_dev *dev_p, char *cp)
        }
 
        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;
 }
@@ -369,75 +378,106 @@ static int blkid_parse_line(blkid_cache cache, blkid_dev *dev_p, char *cp)
  * 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]);