Whamcloud - gitweb
Update release notes, etc., for the 1.46.4 release
[tools/e2fsprogs.git] / lib / blkid / tag.c
index 3948a1e..e88ebc4 100644 (file)
  * %End-Header%
  */
 
+#include "config.h"
+#include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 
 #include "blkidP.h"
 
-#ifdef DEBUG_TAG
-#define DBG(x) x
-#else
-#define DBG(x)
-#endif
-
 static blkid_tag blkid_new_tag(void)
 {
        blkid_tag tag;
@@ -35,22 +31,32 @@ static blkid_tag blkid_new_tag(void)
        return tag;
 }
 
+#ifdef CONFIG_BLKID_DEBUG
+void blkid_debug_dump_tag(blkid_tag tag)
+{
+       if (!tag) {
+               printf("    tag: NULL\n");
+               return;
+       }
+
+       printf("    tag: %s=\"%s\"\n", tag->bit_name, tag->bit_val);
+}
+#endif
+
 void blkid_free_tag(blkid_tag tag)
 {
        if (!tag)
                return;
 
-       DBG(printf("    freeing tag %s=%s\n", tag->bit_name,
+       DBG(DEBUG_TAG, printf("    freeing tag %s=%s\n", tag->bit_name,
                   tag->bit_val ? tag->bit_val : "(NULL)"));
-       DEB_DUMP_TAG(tag);
+       DBG(DEBUG_TAG, blkid_debug_dump_tag(tag));
 
        list_del(&tag->bit_tags);       /* list of tags for this device */
        list_del(&tag->bit_names);      /* list of tags with this type */
 
-       if (tag->bit_name)
-               free(tag->bit_name);
-       if (tag->bit_val)
-               free(tag->bit_val);
+       free(tag->bit_name);
+       free(tag->bit_val);
 
        free(tag);
 }
@@ -76,6 +82,22 @@ blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type)
        return NULL;
 }
 
+extern int blkid_dev_has_tag(blkid_dev dev, const char *type,
+                            const char *value)
+{
+       blkid_tag               tag;
+
+       if (!dev || !type)
+               return -1;
+
+       tag = blkid_find_tag_dev(dev, type);
+       if (!value)
+               return (tag != NULL);
+       if (!tag || strcmp(tag->bit_val, value))
+               return 0;
+       return 1;
+}
+
 /*
  * Find the desired tag type in the cache.
  * We return the head tag for this tag type.
@@ -91,7 +113,8 @@ static blkid_tag blkid_find_head_cache(blkid_cache cache, const char *type)
        list_for_each(p, &cache->bic_tags) {
                tmp = list_entry(p, struct blkid_struct_tag, bit_tags);
                if (!strcmp(tmp->bit_name, type)) {
-                       DBG(printf("    found cache tag head %s\n", type));
+                       DBG(DEBUG_TAG,
+                           printf("    found cache tag head %s\n", type));
                        head = tmp;
                        break;
                }
@@ -101,86 +124,80 @@ static blkid_tag blkid_find_head_cache(blkid_cache cache, const char *type)
 
 /*
  * 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;
+       char            **dev_var = 0;
 
        if (!dev || !name)
                return -BLKID_ERR_PARAM;
 
-repeat:
+       if (!(val = blkid_strndup(value, vlength)) && value)
+               return -BLKID_ERR_MEM;
+
+       /*
+        * Certain common tags are linked directly to the device struct
+        * We need to know what they are before we do anything else because
+        * the function name parameter might get freed later on.
+        */
+       if (!strcmp(name, "TYPE"))
+               dev_var = &dev->bid_type;
+       else if (!strcmp(name, "LABEL"))
+               dev_var = &dev->bid_label;
+       else if (!strcmp(name, "UUID"))
+               dev_var = &dev->bid_uuid;
+
        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;
+               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;
+
+               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;
+
+                               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);
                }
-               dev->bid_flags |= BLKID_BID_FL_MTYPE;
        }
 
-       /* 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);
-               
-       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(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);
-       }
-       
-link_tags:
        /* Link common tags directly to the device struct */
-       if (!strcmp(name, "TYPE") && (!val || !dev->bid_type))
-               dev->bid_type = val;
-       else if (!strcmp(name, "LABEL"))
-               dev->bid_label = val;
-       else if (!strcmp(name, "UUID"))
-               dev->bid_uuid = val;
-               
+       if (dev_var)
+               *dev_var = val;
+
        if (dev->bid_cache)
                dev->bid_cache->bic_flags |= BLKID_BIC_FL_CHANGED;
        return 0;
@@ -188,8 +205,7 @@ link_tags:
 errout:
        if (t)
                blkid_free_tag(t);
-       else if (val)
-               free(val);
+       else free(val);
        if (head)
                blkid_free_tag(head);
        return -BLKID_ERR_MEM;
@@ -210,7 +226,7 @@ int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val)
 {
        char *name, *value, *cp;
 
-       DBG(printf("trying to parse '%s' as a tag\n", token));
+       DBG(DEBUG_TAG, printf("trying to parse '%s' as a tag\n", token));
 
        if (!token || !(cp = strchr(token, '=')))
                return -1;
@@ -245,7 +261,7 @@ errout:
  *
  * These routines do not expose the list.h implementation, which are a
  * contamination of the namespace, and which force us to reveal far, far
- * too much of our internal implemenation.  I'm not convinced I want
+ * too much of our internal implementation.  I'm not convinced I want
  * to keep list.h in the long term, anyway.  It's fine for kernel
  * programming, but performance is not the #1 priority for this
  * library, and I really don't like the tradeoff of type-safety for
@@ -256,7 +272,7 @@ errout:
  * This series of functions iterate over all tags in a device
  */
 #define TAG_ITERATE_MAGIC      0x01a5284c
-       
+
 struct blkid_struct_tag_iterate {
        int                     magic;
        blkid_dev               dev;
@@ -283,7 +299,7 @@ extern int blkid_tag_next(blkid_tag_iterate iter,
                          const char **type, const char **value)
 {
        blkid_tag tag;
-       
+
        *type = 0;
        *value = 0;
        if (!iter || iter->magic != TAG_ITERATE_MAGIC ||
@@ -309,49 +325,147 @@ extern void blkid_tag_iterate_end(blkid_tag_iterate iter)
  * type/value pair.  If there is more than one device that matches the
  * search specification, it returns the one with the highest priority
  * value.  This allows us to give preference to EVMS or LVM devices.
- *
- * XXX there should also be an interface which uses an iterator so we
- * can get all of the devices which match a type/value search parameter.
  */
 extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
                                         const char *type,
                                         const char *value)
 {
-       blkid_tag       head, found;
+       blkid_tag       head;
        blkid_dev       dev;
        int             pri;
        struct list_head *p;
+       int             probe_new = 0;
 
        if (!cache || !type || !value)
                return NULL;
 
-       DBG(printf("looking for %s=%s in cache\n", type, value));
-       
+       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);
 
        if (head) {
                list_for_each(p, &head->bit_names) {
-                       blkid_tag tmp = list_entry(p, struct blkid_struct_tag, 
+                       blkid_tag tmp = list_entry(p, struct blkid_struct_tag,
                                                   bit_names);
 
                        if (!strcmp(tmp->bit_val, value) &&
-                           tmp->bit_dev->bid_pri > pri) {
-                               found = tmp;
-                               dev = found->bit_dev;
+                           (tmp->bit_dev->bid_pri > pri) &&
+                           !access(tmp->bit_dev->bid_name, F_OK)) {
+                               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(cache, dev);
+               if (!dev || (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED)))
+                       goto try_again;
+       }
+
+       if (!dev && !probe_new) {
+               if (blkid_probe_all_new(cache) < 0)
+                       return NULL;
+               probe_new++;
+               goto try_again;
+       }
 
-       if ((!head || !dev) && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) {
-               blkid_probe_all(cache);
+       if (!dev && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) {
+               if (blkid_probe_all(cache) < 0)
+                       return NULL;
                goto try_again;
        }
        return dev;
 }
+
+#ifdef TEST_PROGRAM
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern char *optarg;
+extern int optind;
+#endif
+
+void usage(char *prog)
+{
+       fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask] device "
+               "[type value]\n",
+               prog);
+       fprintf(stderr, "\tList all tags for a device and exit\n");
+       exit(1);
+}
+
+int main(int argc, char **argv)
+{
+       blkid_tag_iterate       iter;
+       blkid_cache             cache = NULL;
+       blkid_dev               dev;
+       int                     c, ret, found;
+       int                     flags = BLKID_DEV_FIND;
+       char                    *tmp;
+       char                    *file = NULL;
+       char                    *devname = NULL;
+       char                    *search_type = NULL;
+       char                    *search_value = NULL;
+       const char              *type, *value;
+
+       while ((c = getopt (argc, argv, "m:f:")) != EOF)
+               switch (c) {
+               case 'f':
+                       file = optarg;
+                       break;
+               case 'm':
+                       blkid_debug_mask = strtoul (optarg, &tmp, 0);
+                       if (*tmp) {
+                               fprintf(stderr, "Invalid debug mask: %s\n",
+                                       optarg);
+                               exit(1);
+                       }
+                       break;
+               case '?':
+                       usage(argv[0]);
+               }
+       if (argc > optind)
+               devname = argv[optind++];
+       if (argc > optind)
+               search_type = argv[optind++];
+       if (argc > optind)
+               search_value = argv[optind++];
+       if (!devname || (argc != optind))
+               usage(argv[0]);
+
+       if ((ret = blkid_get_cache(&cache, file)) != 0) {
+               fprintf(stderr, "%s: error creating cache (%d)\n",
+                       argv[0], ret);
+               exit(1);
+       }
+
+       dev = blkid_get_dev(cache, devname, flags);
+       if (!dev) {
+               fprintf(stderr, "%s: Can not find device in blkid cache\n",
+                       devname);
+               exit(1);
+       }
+       if (search_type) {
+               found = blkid_dev_has_tag(dev, search_type, search_value);
+               printf("Device %s: (%s, %s) %s\n", blkid_dev_devname(dev),
+                      search_type, search_value ? search_value : "NULL",
+                      found ? "FOUND" : "NOT FOUND");
+               return(!found);
+       }
+       printf("Device %s...\n", blkid_dev_devname(dev));
+
+       iter = blkid_tag_iterate_begin(dev);
+       while (blkid_tag_next(iter, &type, &value) == 0) {
+               printf("\tTag %s has value %s\n", type, value);
+       }
+       blkid_tag_iterate_end(iter);
+
+       blkid_put_cache(cache);
+       return (0);
+}
+#endif