Internal changes to the blkid library:

1) Only one tag with a particular name can be attached to a device
at a time.  This significantly simplifies the library, and was needed
to allow the cache file to be re-read and changes integrated into the 
in-core version of the data structure in a simpler fashion than earlier
versions of the library. 

2)  To accomodate this, the ext2/ext3 filesystems are now always tagged
as "ext2" type filesystems.  Ext3 filesystems are tagged with a 
SEC_TYPE tag with the value ext3.

3)  The new blkid_read_cache() function checks the mod time of the
cache file, and if the file has been changed since the last time the
cache file was read into memory, it is re-read.  This function is now
called before probing all of the devices in the system or searching
all devices in the cache for a specific tag value.

4)  After probing all devices, blkid_flush_cache() is called to write
out the cache file.  This assures that all of the hard work involved
in doing a blkid_probe_all() is saved to disk.

diff --git a/lib/blkid/ChangeLog b/lib/blkid/ChangeLog
index 4cb7b93..8fcab4e 100644
--- a/lib/blkid/ChangeLog
+++ b/lib/blkid/ChangeLog
@@ -1,5 +1,38 @@
 2003-02-22  Theodore Ts'o  <tytso@mit.edu>
 
+	* devname.c (blkid_probe_all), tag.c (blkid_find_dev_with_tag): 
+		Call blkid_read_cache to make sure the in-core version of
+		the data structure is the latest.  After probing all of
+		the devices in blkid_probe_all() force the cache file to
+		be written out, the probe_all represents a lot of effort
+		that shouldn't be lost.
+
+	* tag.c (blkid_set_tag): Always replace an existing tag with the
+		new value; we no longer suppor multiple tags with the same
+		value attached to a device, as this was never really
+		supported well, and significantly increased the code
+		complexity.
+
+	* probe.c (probe_ext2): Change handling of ext2/ext3 filesystems.
+		Ext3 filesystems are now always treated as ext2
+		filesystems, with a special SEC_TYPE tag set to ext3.
+		This was necessary because we now longer support multiple
+		tags with the same name attached to a device.
+
+	* save.c (save_dev): Don't special case the TYPE tag; just write
+		it out along with all of the normal tags.
+		(blkid_flush_cache): Eliminate special case code for stdout.
+
+	* cache.c (blkid_new_cache, blkid_get_cache): Eliminate
+		blkid_new_cache and fold into blkid_get_cache (moved to
+		cache.c)
+
+	* read.c (blkid_read_cache): New function created from
+		blkid_get_cache which used to be in read.c that only
+		updates the in-core cache data structure from the file.
+		Uses the file modification time of the cache file to
+		determine whether the cache file needs to be re-read.
+
 	* cache.c, dev.c, devname.c, devno.c, probe.c, read.c, resolve.c,
 		save.c, tag.c, blkidP.h: Add dynamic debugging
 		capabilities, controlled by the environment variable
diff --git a/lib/blkid/blkid.h b/lib/blkid/blkid.h
index de6a982..75b20ad 100644
--- a/lib/blkid/blkid.h
+++ b/lib/blkid/blkid.h
@@ -48,6 +48,7 @@
 
 /* cache.c */
 extern void blkid_put_cache(blkid_cache cache);
+extern int blkid_get_cache(blkid_cache *cache, const char *filename);
 
 /* dev.c */
 extern const char *blkid_dev_devname(blkid_dev dev);
@@ -68,7 +69,6 @@
 extern blkid_loff_t blkid_get_dev_size(int fd);
 
 /* read.c */
-int blkid_get_cache(blkid_cache *cache, const char *filename);
 
 /* resolve.c */
 extern char *blkid_get_tagname_devname(blkid_cache cache, const char *tagname,
diff --git a/lib/blkid/blkidP.h b/lib/blkid/blkidP.h
index db05675..a121106 100644
--- a/lib/blkid/blkidP.h
+++ b/lib/blkid/blkidP.h
@@ -42,7 +42,6 @@
 };
 
 #define BLKID_BID_FL_VERIFIED	0x0001	/* Device data validated from disk */
-#define BLKID_BID_FL_MTYPE	0x0002	/* Device has multiple type matches */
 #define BLKID_BID_FL_INVALID	0x0004	/* Device is invalid */
 
 /*
@@ -87,6 +86,7 @@
 	struct list_head	bic_devs;	/* List head of all devices */
 	struct list_head	bic_tags;	/* List head of all tag types */
 	time_t			bic_time;	/* Last probe time */
+	time_t			bic_ftime; 	/* Mod time of the cachefile */
 	unsigned int		bic_flags;	/* Status flags of the cache */
 	char			*bic_filename;	/* filename of cache */
 };
@@ -96,7 +96,6 @@
 
 extern char *blkid_strdup(const char *s);
 extern char *blkid_strndup(const char *s, const int length);
-extern blkid_cache blkid_new_cache(void);
 
 #define BLKID_CACHE_FILE "/etc/blkid.tab"
 extern const char *blkid_devdirs[];
@@ -209,6 +208,9 @@
 /* probe.c */
 extern blkid_dev blkid_verify_devname(blkid_cache cache, blkid_dev dev);
 
+/* read.c */
+extern void blkid_read_cache(blkid_cache cache);
+
 /* save.c */
 extern int blkid_flush_cache(blkid_cache cache);
 
@@ -218,7 +220,7 @@
 extern void blkid_free_tag(blkid_tag tag);
 extern blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type);
 extern int blkid_set_tag(blkid_dev dev, const char *name,
-			 const char *value, const int vlength, int replace);
+			 const char *value, const int vlength);
 
 /*
  * Functions to create and find a specific tag type: dev.c
diff --git a/lib/blkid/cache.c b/lib/blkid/cache.c
index 9312416..50d52a0 100644
--- a/lib/blkid/cache.c
+++ b/lib/blkid/cache.c
@@ -15,7 +15,7 @@
 
 int blkid_debug_mask;
 
-blkid_cache blkid_new_cache(void)
+int blkid_get_cache(blkid_cache *ret_cache, const char *filename)
 {
 	blkid_cache cache;
 
@@ -29,15 +29,23 @@
 	}
 #endif
 
-	DBG(DEBUG_CACHE, printf("initializing empty cache\n"));
+	DBG(DEBUG_CACHE, printf("creating blkid cache (using %s)\n",
+				filename ? filename : "default cache"));
 
 	if (!(cache = (blkid_cache) calloc(1, sizeof(struct blkid_struct_cache))))
-		return NULL;
+		return -BLKID_ERR_MEM;
 
 	INIT_LIST_HEAD(&cache->bic_devs);
 	INIT_LIST_HEAD(&cache->bic_tags);
 
-	return cache;
+	if (!filename || !strlen(filename))
+		filename = BLKID_CACHE_FILE;
+	cache->bic_filename = blkid_strdup(filename);
+	
+	blkid_read_cache(cache);
+	
+	*ret_cache = cache;
+	return 0;
 }
 
 void blkid_put_cache(blkid_cache cache)
@@ -97,8 +105,9 @@
 			argv[1] ? argv[1] : BLKID_CACHE_FILE);
 		exit(1);
 	}
-	if ((cache = blkid_new_cache()) == NULL) {
-		fprintf(stderr, "%s: error creating cache\n", argv[0]);
+	if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) {
+		fprintf(stderr, "%s: error creating cache (%d)\n",
+			argv[0], ret);
 		exit(1);
 	}
 	if ((ret = blkid_probe_all(cache) < 0))
diff --git a/lib/blkid/devname.c b/lib/blkid/devname.c
index 7d88551..27a9d0c 100644
--- a/lib/blkid/devname.c
+++ b/lib/blkid/devname.c
@@ -280,6 +280,7 @@
 	    time(0) - cache->bic_time < BLKID_PROBE_INTERVAL)
 		return 0;
 
+	blkid_read_cache(cache);
 	evms_probe_all(cache);
 #ifdef VG_DIR
 	lvm_probe_all(cache);
@@ -340,6 +341,7 @@
 
 	cache->bic_time = time(0);
 	cache->bic_flags |= BLKID_BIC_FL_PROBED;
+	blkid_flush_cache(cache);
 	return 0;
 }
 
@@ -347,6 +349,7 @@
 int main(int argc, char **argv)
 {
 	blkid_cache cache = NULL;
+	int ret;
 
 	blkid_debug_mask = DEBUG_ALL;
 	if (argc != 1) {
@@ -354,8 +357,9 @@
 			"Probe all devices and exit\n", argv[0]);
 		exit(1);
 	}
-	if ((cache = blkid_new_cache()) == NULL) {
-		fprintf(stderr, "%s: error creating cache\n", argv[0]);
+	if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) {
+		fprintf(stderr, "%s: error creating cache (%d)\n",
+			argv[0], ret);
 		exit(1);
 	}
 	if (blkid_probe_all(cache) < 0)
diff --git a/lib/blkid/probe.c b/lib/blkid/probe.c
index 4f76ba5..2484a5f 100644
--- a/lib/blkid/probe.c
+++ b/lib/blkid/probe.c
@@ -74,15 +74,15 @@
 
 	if (!uuid_is_null(uuid)) {
 		uuid_unparse(uuid, str);
-		blkid_set_tag(dev, "UUID", str, sizeof(str), 1);
+		blkid_set_tag(dev, "UUID", str, sizeof(str));
 	}
 }
 
 static int probe_ext2(int fd, blkid_cache cache, blkid_dev dev,
-		      struct blkid_magic *id, unsigned char *buf,
-		      const char **ret_sectype)
+		      struct blkid_magic *id, unsigned char *buf)
 {
 	struct ext2_super_block *es;
+	const char *sec_type = 0;
 
 	es = (struct ext2_super_block *)buf;
 
@@ -91,26 +91,28 @@
 		   blkid_le32(es->s_feature_incompat),
 		   blkid_le32(es->s_feature_ro_compat)));
 
-	/* Make sure we don't keep re-probing as ext2 for a journaled fs */
-	if (!strcmp(id->bim_type, "ext2") &&
-	    ((blkid_le32(es->s_feature_compat) &
-	      EXT3_FEATURE_COMPAT_HAS_JOURNAL) ||
-	     (blkid_le32(es->s_feature_incompat) &
-	      EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)))
+	/* Distinguish between jbd and ext2/3 fs */
+	if (id && (blkid_le32(es->s_feature_incompat) &
+		   EXT3_FEATURE_INCOMPAT_JOURNAL_DEV))
 		return -BLKID_ERR_PARAM;
 
 	if (strlen(es->s_volume_name))
 		blkid_set_tag(dev, "LABEL", es->s_volume_name,
-			      sizeof(es->s_volume_name), 1);
+			      sizeof(es->s_volume_name));
 
 	set_uuid(dev, es->s_uuid);
 
+	if (blkid_le32(es->s_feature_compat) &
+	    EXT3_FEATURE_COMPAT_HAS_JOURNAL)
+		sec_type = "ext3";
+	
+	blkid_set_tag(dev, "SEC_TYPE", sec_type, 0);
+
 	return 0;
 }
 
 static int probe_jbd(int fd, blkid_cache cache, blkid_dev dev, 
-		     struct blkid_magic *id, unsigned char *buf,
-		     const char **ret_sectype)
+		     struct blkid_magic *id, unsigned char *buf)
 {
 	struct ext2_super_block *es = (struct ext2_super_block *) buf;
 
@@ -118,33 +120,11 @@
 	      EXT3_FEATURE_INCOMPAT_JOURNAL_DEV))
 		return -BLKID_ERR_PARAM;
 
-	return (probe_ext2(fd, cache, dev, id, buf, ret_sectype));
-}
-
-static int probe_ext3(int fd, blkid_cache cache, blkid_dev dev,
-		      struct blkid_magic *id, unsigned char *buf,
-		      const char **ret_sectype)
-{
-	struct ext2_super_block *es = (struct ext2_super_block *) buf;
-	int ret;
-
-	if (!(blkid_le32(es->s_feature_compat) &
-	      EXT3_FEATURE_COMPAT_HAS_JOURNAL))
-		return -BLKID_ERR_PARAM;
-
-	if ((ret = probe_ext2(fd, cache, dev, id, buf, ret_sectype)) < 0)
-		return ret;
-
-	if (!(blkid_le32(es->s_feature_incompat) &
-	      EXT3_FEATURE_INCOMPAT_RECOVER))
-		*ret_sectype = "ext2";
-
-	return 0;
+	return (probe_ext2(fd, cache, dev, 0, buf));
 }
 
 static int probe_vfat(int fd, blkid_cache cache, blkid_dev dev,
-		      struct blkid_magic *id, unsigned char *buf,
-		      const char **ret_sectype)
+		      struct blkid_magic *id, unsigned char *buf)
 {
 	struct vfat_super_block *vs;
 	char serno[10];
@@ -158,20 +138,19 @@
 			--end;
 		if (end >= vs->vs_label)
 			blkid_set_tag(dev, "LABEL", vs->vs_label,
-				      end - vs->vs_label + 1, 1);
+				      end - vs->vs_label + 1);
 	}
 
 	/* We can't just print them as %04X, because they are unaligned */
 	sprintf(serno, "%02X%02X-%02X%02X", vs->vs_serno[3], vs->vs_serno[2],
 		vs->vs_serno[1], vs->vs_serno[0]);
-	blkid_set_tag(dev, "UUID", serno, sizeof(serno), 1);
+	blkid_set_tag(dev, "UUID", serno, sizeof(serno));
 
 	return 0;
 }
 
 static int probe_msdos(int fd, blkid_cache cache, blkid_dev dev,
-		       struct blkid_magic *id, unsigned char *buf,
-		       const char **ret_sectype)
+		       struct blkid_magic *id, unsigned char *buf)
 {
 	struct msdos_super_block *ms = (struct msdos_super_block *) buf;
 	char serno[10];
@@ -183,20 +162,19 @@
 			--end;
 		if (end >= ms->ms_label)
 			blkid_set_tag(dev, "LABEL", ms->ms_label,
-				      end - ms->ms_label + 1, 1);
+				      end - ms->ms_label + 1);
 	}
 
 	/* We can't just print them as %04X, because they are unaligned */
 	sprintf(serno, "%02X%02X-%02X%02X", ms->ms_serno[3], ms->ms_serno[2],
 		ms->ms_serno[1], ms->ms_serno[0]);
-	blkid_set_tag(dev, "UUID", serno, 0, 1);
+	blkid_set_tag(dev, "UUID", serno, 0);
 
 	return 0;
 }
 
 static int probe_xfs(int fd, blkid_cache cache, blkid_dev dev,
-		     struct blkid_magic *id, unsigned char *buf,
-		     const char **ret_sectype)
+		     struct blkid_magic *id, unsigned char *buf)
 {
 	struct xfs_super_block *xs;
 
@@ -204,14 +182,13 @@
 
 	if (strlen(xs->xs_fname))
 		blkid_set_tag(dev, "LABEL", xs->xs_fname,
-			      sizeof(xs->xs_fname), 1);
+			      sizeof(xs->xs_fname));
 	set_uuid(dev, xs->xs_uuid);
 	return 0;
 }
 
 static int probe_reiserfs(int fd, blkid_cache cache, blkid_dev dev,
-			  struct blkid_magic *id, unsigned char *buf,
-			  const char **ret_sectype)
+			  struct blkid_magic *id, unsigned char *buf)
 {
 	struct reiserfs_super_block *rs = (struct reiserfs_super_block *) buf;
 	unsigned int blocksize;
@@ -227,7 +204,7 @@
 	    !strcmp(id->bim_magic, "ReIsEr3Fs")) {
 		if (strlen(rs->rs_label)) {
 			blkid_set_tag(dev, "LABEL", rs->rs_label,
-				      sizeof(rs->rs_label), 1);
+				      sizeof(rs->rs_label));
 		}
 
 		set_uuid(dev, rs->rs_uuid);
@@ -253,7 +230,6 @@
 static struct blkid_magic type_array[] = {
 /*  type     kboff   sboff len  magic			probe */
   { "jbd",	 1,   0x38,  2, "\123\357",		probe_jbd },
-  { "ext3",	 1,   0x38,  2, "\123\357",		probe_ext3 },
   { "ext2",	 1,   0x38,  2, "\123\357",		probe_ext2 },
   { "reiserfs",	 8,   0x34,  8, "ReIsErFs",		probe_reiserfs },
   { "reiserfs", 64,   0x34,  9, "ReIsEr2Fs",		probe_reiserfs },
@@ -300,17 +276,6 @@
 };
 
 /*
- * If a device's filesystem no longer checks out, we need to nuke
- * information about it from the entry.
- */
-static void blkid_invalidate_fs(blkid_dev dev)
-{
-	blkid_set_tag(dev, "TYPE", 0, 0, 0);
-	blkid_set_tag(dev, "LABEL", 0, 0, 0);
-	blkid_set_tag(dev, "UUID", 0, 0, 0);
-}	
-
-/*
  * Verify that the data in dev is consistent with what is on the actual
  * block device (using the devname field only).  Normally this will be
  * called when finding items in the cache, but for long running processes
@@ -323,7 +288,7 @@
 {
 	struct blkid_magic *id;
 	unsigned char *bufs[BLKID_BLK_OFFS + 1], *buf;
-	const char *sec_type, *type;
+	const char *type;
 	struct stat st;
 	time_t diff;
 	int fd, idx;
@@ -364,7 +329,6 @@
 	 */
 try_again:
 	type = 0;
-	sec_type = 0;
 	if (!dev->bid_type || !strcmp(dev->bid_type, "mdraid")) {
 		uuid_t	uuid;
 
@@ -402,7 +366,7 @@
 			continue;
 
 		if ((id->bim_probe == NULL) ||
-		    (id->bim_probe(fd, cache, dev, id, buf, &sec_type) == 0)) {
+		    (id->bim_probe(fd, cache, dev, id, buf) == 0)) {
 			type = id->bim_type;
 			goto found_type;
 		}
@@ -412,7 +376,10 @@
 		/*
 		 * Zap the device filesystem type and try again
 		 */
-		blkid_invalidate_fs(dev);
+		blkid_set_tag(dev, "TYPE", 0, 0);
+		blkid_set_tag(dev, "SEC_TYPE", 0, 0);
+		blkid_set_tag(dev, "LABEL", 0, 0);
+		blkid_set_tag(dev, "UUID", 0, 0);
 		goto try_again;
 	}
 
@@ -428,9 +395,7 @@
 		dev->bid_flags |= BLKID_BID_FL_VERIFIED;
 		cache->bic_flags |= BLKID_BIC_FL_CHANGED;
 
-		blkid_set_tag(dev, "TYPE", type, 0, 1);
-		if (sec_type)
-			blkid_set_tag(dev, "TYPE", sec_type, 0, 0);
+		blkid_set_tag(dev, "TYPE", type, 0);
 				
 		DBG(DEBUG_PROBE, printf("%s: devno 0x%04Lx, type %s\n",
 			   dev->bid_name, st.st_rdev, type));
@@ -446,6 +411,7 @@
 {
 	blkid_dev dev;
 	blkid_cache cache;
+	int ret;
 
 	blkid_debug_mask = DEBUG_ALL;
 	if (argc != 2) {
@@ -453,7 +419,11 @@
 			"Probe a single device to determine type\n", argv[0]);
 		exit(1);
 	}
-	cache = blkid_new_cache();
+	if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) {
+		fprintf(stderr, "%s: error creating cache (%d)\n",
+			argv[0], ret);
+		exit(1);
+	}
 	dev = blkid_get_dev(cache, argv[1], BLKID_DEV_NORMAL);
 	if (!dev) {
 		printf("%s: %s has an unsupported type\n", argv[0], argv[1]);
diff --git a/lib/blkid/probe.h b/lib/blkid/probe.h
index 3e02604..391428c 100644
--- a/lib/blkid/probe.h
+++ b/lib/blkid/probe.h
@@ -19,8 +19,7 @@
 struct blkid_magic;
 
 typedef int (*blkid_probe_t)(int fd, blkid_cache cache, blkid_dev dev, 
-			     struct blkid_magic *id, unsigned char *buf,
-			     const char **ret_sectype);
+			     struct blkid_magic *id, unsigned char *buf);
 
 struct blkid_magic {
 	const char	*bim_type;	/* type name for this magic */
diff --git a/lib/blkid/read.c b/lib/blkid/read.c
index fdee756..71618e3 100644
--- a/lib/blkid/read.c
+++ b/lib/blkid/read.c
@@ -14,7 +14,9 @@
 #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>
@@ -312,7 +314,7 @@
 		/* FIXME: need to parse a long long eventually */
 		dev->bid_time = strtol(value, 0, 0);
 	else
-		ret = blkid_set_tag(dev, name, value, strlen(value), 0);
+		ret = blkid_set_tag(dev, name, value, strlen(value));
 
 	DBG(DEBUG_READ, printf("    tag: %s=\"%s\"\n", name, value));
 
@@ -367,40 +369,37 @@
  * 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;
+		return;
 
-	if ((*cache = blkid_new_cache()) == NULL)
-		return -BLKID_ERR_MEM;
-
-	if (!filename || !strlen(filename))
-		filename = BLKID_CACHE_FILE;
-	else
-		(*cache)->bic_filename = blkid_strdup(filename);
-
-	DBG(DEBUG_READ|DEBUG_CACHE, printf("reading 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 0;
+	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;
@@ -410,12 +409,12 @@
 		lineno++;
 		/* 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) {
+		if (blkid_parse_line(cache, &dev, buf) < 0) {
 			DBG(DEBUG_READ,
 			    printf("blkid: bad format on line %d\n", lineno));
 			continue;
@@ -424,12 +423,13 @@
 	/*
 	 * 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;
+errout:
+	close(fd);
+	return;
 }
 
 #ifdef TEST_PROGRAM
diff --git a/lib/blkid/resolve.c b/lib/blkid/resolve.c
index 7e729cb..62764c7 100644
--- a/lib/blkid/resolve.c
+++ b/lib/blkid/resolve.c
@@ -70,8 +70,6 @@
 
 	if (!cache) {
 		if (blkid_get_cache(&c, NULL) < 0)
-			c = blkid_new_cache();
-		if (!c)
 			return NULL;
 	}
 
@@ -115,7 +113,7 @@
 			argv[0], argv[0]);
 		exit(1);
 	}
-	if (blkid_get_cache(&cache, 0) < 0) {
+	if (blkid_get_cache(&cache, "/dev/null") < 0) {
 		fprintf(stderr, "Couldn't get blkid cache\n");
 		exit(1);
 	}
diff --git a/lib/blkid/save.c b/lib/blkid/save.c
index 82b9b77..bed211a 100644
--- a/lib/blkid/save.c
+++ b/lib/blkid/save.c
@@ -37,14 +37,13 @@
 	    printf("device %s, type %s\n", dev->bid_name, dev->bid_type));
 
 	fprintf(file,
-		"<device TYPE=\"%s\" DEVNO=\"0x%04lx\" TIME=\"%lu\"",
-		dev->bid_type, (unsigned long) dev->bid_devno, dev->bid_time);
+		"<device DEVNO=\"0x%04lx\" TIME=\"%lu\"",
+		(unsigned long) dev->bid_devno, dev->bid_time);
 	if (dev->bid_pri)
 		fprintf(file, " PRI=\"%d\"", dev->bid_pri);
 	list_for_each(p, &dev->bid_tags) {
 		blkid_tag tag = list_entry(p, struct blkid_struct_tag, bit_tags);
-		if (strcmp(tag->bit_name, "TYPE"))
-			fprintf(file, " %s=\"%s\"", tag->bit_name,tag->bit_val);
+		fprintf(file, " %s=\"%s\"", tag->bit_name,tag->bit_val);
 	}
 	fprintf(file, ">%s</device>\n", dev->bid_name);
 
@@ -62,65 +61,61 @@
 	const char *filename;
 	FILE *file = NULL;
 	int fd, ret = 0;
+	struct stat st;
 
 	if (!cache)
 		return -BLKID_ERR_PARAM;
 
 	if (list_empty(&cache->bic_devs) ||
 	    !(cache->bic_flags & BLKID_BIC_FL_CHANGED)) {
-		DBG(DEBUG_SAVE, printf("empty cache, not saving\n"));
+		DBG(DEBUG_SAVE, printf("skipping cache file write\n"));
 		return 0;
 	}
 
 	filename = cache->bic_filename ? cache->bic_filename: BLKID_CACHE_FILE;
 
-	if (!strcmp(filename, "-"))
-		file = stdout;
-	else {
-		struct stat st;
-
-		/* If we can't write to the cache file, then don't even try */
-		if (((ret = stat(filename, &st)) < 0 && errno != ENOENT) ||
-		    (ret == 0 && access(filename, W_OK) < 0)) {
-			DBG(DEBUG_SAVE,
-			    printf("can't write to cache file %s\n", filename));
-			return 0;
-		}
-
-		/*
-		 * Try and create a temporary file in the same directory so
-		 * that in case of error we don't overwrite the cache file.
-		 * If the cache file doesn't yet exist, it isn't a regular
-		 * file (e.g. /dev/null or a socket), or we couldn't create
-		 * a temporary file then we open it directly.
-		 */
-		if (ret == 0 && S_ISREG(st.st_mode)) {
-			tmp = malloc(strlen(filename) + 8);
-			if (tmp) {
-				sprintf(tmp, "%s-XXXXXX", filename);
-				fd = mkstemp(tmp);
-				if (fd >= 0) {
-					file = fdopen(fd, "w");
-					opened = tmp;
-				}
-				fchmod(fd, 0644);
-			}
-		}
-
-		if (!file) {
-			file = fopen(filename, "w");
-			opened = filename;
-		}
-
+	/* If we can't write to the cache file, then don't even try */
+	if (((ret = stat(filename, &st)) < 0 && errno != ENOENT) ||
+	    (ret == 0 && access(filename, W_OK) < 0)) {
 		DBG(DEBUG_SAVE,
-		    printf("cache file %s (really %s)\n", filename, opened));
+		    printf("can't write to cache file %s\n", filename));
+		return 0;
+	}
 
-		if (!file) {
-			ret = errno;
-			goto errout;
+	/*
+	 * Try and create a temporary file in the same directory so
+	 * that in case of error we don't overwrite the cache file.
+	 * If the cache file doesn't yet exist, it isn't a regular
+	 * file (e.g. /dev/null or a socket), or we couldn't create
+	 * a temporary file then we open it directly.
+	 */
+	if (ret == 0 && S_ISREG(st.st_mode)) {
+		tmp = malloc(strlen(filename) + 8);
+		if (tmp) {
+			sprintf(tmp, "%s-XXXXXX", filename);
+			fd = mkstemp(tmp);
+			if (fd >= 0) {
+				file = fdopen(fd, "w");
+				opened = tmp;
+			}
+			fchmod(fd, 0644);
 		}
 	}
 
+	if (!file) {
+		file = fopen(filename, "w");
+		opened = filename;
+	}
+
+	DBG(DEBUG_SAVE,
+	    printf("writing cache file %s (really %s)\n",
+		   filename, opened));
+
+	if (!file) {
+		ret = errno;
+		goto errout;
+	}
+
 	list_for_each(p, &cache->bic_devs) {
 		blkid_dev dev = list_entry(p, struct blkid_struct_dev, bid_devs);
 		if (!dev->bid_type)
@@ -134,27 +129,25 @@
 		ret = 1;
 	}
 
-	if (file != stdout) {
-		fclose(file);
-		if (opened != filename) {
-			if (ret < 0) {
-				unlink(opened);
-				DBG(DEBUG_SAVE,
-				    printf("unlinked temp cache %s\n", opened));
-			} else {
-				char *backup;
+	fclose(file);
+	if (opened != filename) {
+		if (ret < 0) {
+			unlink(opened);
+			DBG(DEBUG_SAVE,
+			    printf("unlinked temp cache %s\n", opened));
+		} else {
+			char *backup;
 
-				backup = malloc(strlen(filename) + 5);
-				if (backup) {
-					sprintf(backup, "%s.old", filename);
-					unlink(backup);
-					link(filename, backup);
-					free(backup);
-				}
-				rename(opened, filename);
-				DBG(DEBUG_SAVE,
-				    printf("moved temp cache %s\n", opened));
+			backup = malloc(strlen(filename) + 5);
+			if (backup) {
+				sprintf(backup, "%s.old", filename);
+				unlink(backup);
+				link(filename, backup);
+				free(backup);
 			}
+			rename(opened, filename);
+			DBG(DEBUG_SAVE,
+			    printf("moved temp cache %s\n", opened));
 		}
 	}
 
@@ -177,8 +170,9 @@
 		exit(1);
 	}
 
-	if ((cache = blkid_new_cache()) == NULL) {
-		fprintf(stderr, "%s: error creating cache\n", argv[0]);
+	if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) {
+		fprintf(stderr, "%s: error creating cache (%d)\n",
+			argv[0], ret);
 		exit(1);
 	}
 	if ((ret = blkid_probe_all(cache)) < 0) {
diff --git a/lib/blkid/tag.c b/lib/blkid/tag.c
index e8b54f4..d3db41c 100644
--- a/lib/blkid/tag.c
+++ b/lib/blkid/tag.c
@@ -97,15 +97,10 @@
 /*
  * Set a tag on an existing device.
  * 
- * If replace is non-zero, blkid_set_tag() will replace the existing
- * tag with the specified value.  Otherwise, it will add the specified
- * tag to the device.
- *
- * If value is NULL, then delete all tags with that name from the
- * device.
+ * If value is NULL, then delete the tagsfrom the device.
  */
 int blkid_set_tag(blkid_dev dev, const char *name,
-		  const char *value, const int vlength, int replace)
+		  const char *value, const int vlength)
 {
 	blkid_tag	t = 0, head = 0;
 	char		*val = 0;
@@ -113,64 +108,52 @@
 	if (!dev || !name)
 		return -BLKID_ERR_PARAM;
 
-repeat:
+	if (!(val = blkid_strndup(value, vlength)))
+		return -BLKID_ERR_MEM;
 	t = blkid_find_tag_dev(dev, name);
-	val = blkid_strndup(value, vlength);
 	if (!value) {
-		if (t) {
+		if (t)
 			blkid_free_tag(t);
-			goto repeat;
-		} else
-			goto link_tags;
-	}
-	if (!val)
-		goto errout;
-	if (t) {
+	} else if (t) {
 		if (!strcmp(t->bit_val, val)) {
 			/* Same thing, exit */
 			free(val);
 			return 0;
 		}
-		if (replace) {
-			free(t->bit_val);
-			t->bit_val = val;
-			goto link_tags;
-		}
-		dev->bid_flags |= BLKID_BID_FL_MTYPE;
-	}
+		free(t->bit_val);
+		t->bit_val = val;
+	} else {
+		/* Existing tag not present, add to device */
+		if (!(t = blkid_new_tag()))
+			goto errout;
+		t->bit_name = blkid_strdup(name);
+		t->bit_val = val;
+		t->bit_dev = dev;
 
-	/* Existing tag not present, add to device */
-	t = blkid_new_tag();
-	if (!t)
-		goto errout;
-	t->bit_name = blkid_strdup(name);
-	t->bit_val = val;
-	t->bit_dev = dev;
-
-	list_add_tail(&t->bit_tags, &dev->bid_tags);
+		list_add_tail(&t->bit_tags, &dev->bid_tags);
 		
-	if (dev->bid_cache) {
-		head = blkid_find_head_cache(dev->bid_cache, t->bit_name);
-		if (!head) {
-			head = blkid_new_tag();
-			if (!head)
-				goto errout;
+		if (dev->bid_cache) {
+			head = blkid_find_head_cache(dev->bid_cache,
+						     t->bit_name);
+			if (!head) {
+				head = blkid_new_tag();
+				if (!head)
+					goto errout;
 
-			DBG(DEBUG_TAG,
-			    printf("    creating new cache tag head %s\n",
-				   name));
-			head->bit_name = blkid_strdup(name);
-			if (!head->bit_name)
-				goto errout;
-			list_add_tail(&head->bit_tags,
-				      &dev->bid_cache->bic_tags);
+				DBG(DEBUG_TAG,
+				    printf("    creating new cache tag head %s\n", name));
+				head->bit_name = blkid_strdup(name);
+				if (!head->bit_name)
+					goto errout;
+				list_add_tail(&head->bit_tags,
+					      &dev->bid_cache->bic_tags);
+			}
+			list_add_tail(&t->bit_names, &head->bit_names);
 		}
-		list_add_tail(&t->bit_names, &head->bit_names);
 	}
 	
-link_tags:
 	/* Link common tags directly to the device struct */
-	if (!strcmp(name, "TYPE") && (!val || !dev->bid_type))
+	if (!strcmp(name, "TYPE"))
 		dev->bid_type = val;
 	else if (!strcmp(name, "LABEL"))
 		dev->bid_label = val;
@@ -313,7 +296,7 @@
 					 const char *type,
 					 const char *value)
 {
-	blkid_tag	head, found;
+	blkid_tag	head;
 	blkid_dev	dev;
 	int		pri;
 	struct list_head *p;
@@ -321,11 +304,12 @@
 	if (!cache || !type || !value)
 		return NULL;
 
+	blkid_read_cache(cache);
+	
 	DBG(DEBUG_TAG, printf("looking for %s=%s in cache\n", type, value));
 	
 try_again:
 	pri = -1;
-	found = 0;
 	dev = 0;
 	head = blkid_find_head_cache(cache, type);
 
@@ -336,15 +320,16 @@
 
 			if (!strcmp(tmp->bit_val, value) &&
 			    tmp->bit_dev->bid_pri > pri) {
-				found = tmp;
-				dev = found->bit_dev;
+				dev = tmp->bit_dev;
 				pri = dev->bid_pri;
 			}
 		}
 	}
-	dev = blkid_verify_devname(cache, dev);
-	if (dev && strcmp(found->bit_val, value))
-		dev = 0;
+	if (dev && !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) {
+		dev = blkid_verify_devname(cache, dev);
+		if (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED))
+			goto try_again;
+	}
 
 	if (!dev && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) {
 		blkid_probe_all(cache);