2 * dev.c - allocation/initialization/free routines for dev
4 * Copyright (C) 2001 Andreas Dilger
7 * This file may be redistributed under the terms of the
8 * GNU Lesser General Public License.
15 #include "blkid/blkid.h"
19 #define DEB_DEV(fmt, arg...) printf("dev: " fmt, ## arg)
21 #define DEB_DEV(fmt, arg...) do {} while (0)
24 blkid_dev *blkid_new_dev(void)
28 if (!(dev = (blkid_dev *)calloc(1, sizeof(blkid_dev))))
31 INIT_LIST_HEAD(&dev->bid_devs);
32 INIT_LIST_HEAD(&dev->bid_tags);
37 void blkid_free_dev(blkid_dev *dev)
42 DEB_DEV(" freeing dev %s (%s)\n", dev->bid_name, dev->bid_type);
45 list_del(&dev->bid_devs);
46 while (!list_empty(&dev->bid_tags)) {
47 blkid_tag *tag = list_entry(dev->bid_tags.next, blkid_tag,
52 string_free(dev->bid_name);
57 * This is kind of ugly, but I want to be able to compare two strings in
58 * several different ways. For example, in some cases, if both strings
59 * are NULL, those would be considered different, but in other cases
60 * they would be considered the same. Hence the ugliness.
62 * Use as: "ret == SC_SAME" if both strings exist and are equal
63 * this is equivalent to "!(ret & SC_DIFF)"
64 * "ret & SC_SAME" if both strings being NULL is also equal
65 * this is equivalent to "!(ret == SC_DIFF)"
66 * "ret == SC_DIFF" if both strings exist and are different
67 * this is equivalent to "!(ret & SC_SAME)"
68 * "ret & SC_DIFF" if both strings being NULL is also different
69 * this is equivalent to "!(ret == SC_SAME)"
70 * "ret == SC_NONE" to see if both strings do not exist
72 #define SC_DIFF 0x0001
73 #define SC_NONE 0x0003
74 #define SC_SAME 0x0002
76 int string_compare(char *s1, char *s2)
91 * Add a tag to the global cache tag list.
93 static int add_tag_to_cache(blkid_cache *cache, blkid_tag *tag)
95 blkid_tag *head = NULL;
100 DEB_DEV(" adding tag %s=%s to cache\n", tag->bit_name, tag->bit_val);
102 if (!(head = blkid_find_head_cache(cache, tag))) {
103 head = blkid_new_tag();
105 return -BLKID_ERR_MEM;
107 DEB_DEV(" creating new cache tag head %s\n",tag->bit_name);
108 head->bit_name = string_copy(tag->bit_name);
109 if (!head->bit_name) {
110 blkid_free_tag(head);
111 return -BLKID_ERR_MEM;
114 list_add_tail(&head->bit_tags, &cache->bic_tags);
117 /* Add this tag to global list */
118 list_add_tail(&tag->bit_names, &head->bit_names);
124 * Add a device to the global cache list, along with all its tags.
126 blkid_dev *blkid_add_dev_to_cache(blkid_cache *cache, blkid_dev *dev)
134 dev->bid_id = ++(cache->bic_idmax);
136 list_for_each(p, &cache->bic_devs) {
137 blkid_dev *odev = list_entry(p, blkid_dev, bid_devs);
138 int dup_uuid, dup_label, dup_name, dup_type;
140 dup_name = string_compare(odev->bid_name, dev->bid_name);
141 dup_label = string_compare(odev->bid_label, dev->bid_label);
142 dup_uuid = string_compare(odev->bid_uuid, dev->bid_uuid);
144 if (odev->bid_id == dev->bid_id)
145 dev->bid_id = ++(cache->bic_idmax);
147 /* Fields different, do nothing (check more fields?) */
148 if ((dup_name & SC_DIFF) && (dup_uuid & SC_DIFF) &&
149 (dup_label & SC_DIFF))
152 /* We can't simply allow duplicate fields if the bid_type is
153 * different, given that a filesystem may change from ext2
154 * to ext3 but it will have the same UUID and LABEL fields.
155 * We need to discard the old cache entry in this case.
158 /* If the UUIDs are the same but one is unverified discard it */
159 if (dup_uuid == SC_SAME) {
160 DEB_DEV(" duplicate uuid %s\n", dev->bid_uuid);
161 if (!(odev->bid_flags & BLKID_BID_FL_VERIFIED)) {
162 dev->bid_id = odev->bid_id; /* keep old id */
163 blkid_free_dev(odev);
165 } else if (!(dev->bid_flags & BLKID_BID_FL_VERIFIED)) {
171 /* This shouldn't happen */
172 fprintf(stderr, "blkid: same UUID for %s and %s\n",
173 dev->bid_name, odev->bid_name);
176 /* If the device name is the same, discard one of them
177 * (prefer one that has been validated, or the first one).
179 if (dup_name == SC_SAME) {
180 DEB_DEV(" duplicate devname %s\n", dev->bid_name);
181 if (odev->bid_flags & BLKID_BID_FL_VERIFIED ||
182 !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) {
183 if ((dup_uuid & SC_SAME) &&
184 (dup_label & SC_SAME)) /* use old id */
185 dev->bid_id = odev->bid_id;
190 blkid_free_dev(odev);
195 dup_type = string_compare(odev->bid_type, dev->bid_type);
197 if (dup_label == SC_SAME && dup_type == SC_SAME) {
198 DEB_DEV(" duplicate label %s\n", dev->bid_label);
199 if (!(odev->bid_flags & BLKID_BID_FL_VERIFIED)) {
200 blkid_free_dev(odev);
202 } else if (!(dev->bid_flags & BLKID_BID_FL_VERIFIED)) {
207 fprintf(stderr, "blkid: same LABEL for %s and %s\n",
208 dev->bid_name, odev->bid_name);
213 DEB_DEV(" adding new devname %s to cache\n", dev->bid_name);
215 cache->bic_flags |= BLKID_BIC_FL_CHANGED;
217 list_add_tail(&dev->bid_devs, &cache->bic_devs);
218 list_for_each(p, &dev->bid_tags) {
219 blkid_tag *tag = list_entry(p, blkid_tag, bit_tags);
220 add_tag_to_cache(cache, tag);
225 DEB_DEV(" using old devname %s from cache\n", dev->bid_name);
230 int main(int argc, char** argv)
233 blkid_dev *dev, *newdev;
236 fprintf(stderr, "Usage:\t%s dev1 dev2\n"
237 "Test that adding the same device to the cache fails\n",
242 cache = blkid_new_cache();
247 dev = blkid_devname_to_dev(argv[1], 0);
248 newdev = blkid_add_dev_to_cache(cache, dev);
250 printf("devices changed for %s (unexpected)\n", argv[1]);
251 dev = blkid_devname_to_dev(argv[2], 0);
252 newdev = blkid_add_dev_to_cache(cache, dev);
254 printf("devices changed for %s (unexpected)\n", argv[2]);
255 dev = blkid_devname_to_dev(argv[2], 0);
256 newdev = blkid_add_dev_to_cache(cache, dev);
258 printf("devices changed for %s (expected)\n", argv[2]);
260 blkid_free_cache(cache);