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.
24 blkid_dev blkid_new_dev(void)
28 if (!(dev = (blkid_dev) calloc(1, sizeof(struct blkid_struct_dev))))
31 INIT_LIST_HEAD(&dev->bid_devs);
32 INIT_LIST_HEAD(&dev->bid_tags);
37 void blkid_free_dev(blkid_dev dev)
42 DBG(printf(" 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,
48 struct blkid_struct_tag,
53 string_free(dev->bid_name);
58 * This is kind of ugly, but I want to be able to compare two strings in
59 * several different ways. For example, in some cases, if both strings
60 * are NULL, those would be considered different, but in other cases
61 * they would be considered the same. Hence the ugliness.
63 * Use as: "ret == SC_SAME" if both strings exist and are equal
64 * this is equivalent to "!(ret & SC_DIFF)"
65 * "ret & SC_SAME" if both strings being NULL is also equal
66 * this is equivalent to "!(ret == SC_DIFF)"
67 * "ret == SC_DIFF" if both strings exist and are different
68 * this is equivalent to "!(ret & SC_SAME)"
69 * "ret & SC_DIFF" if both strings being NULL is also different
70 * this is equivalent to "!(ret == SC_SAME)"
71 * "ret == SC_NONE" to see if both strings do not exist
73 #define SC_DIFF 0x0001
74 #define SC_NONE 0x0003
75 #define SC_SAME 0x0002
77 static int string_compare(char *s1, char *s2)
92 * Add a tag to the global cache tag list.
94 static int add_tag_to_cache(blkid_cache cache, blkid_tag tag)
96 blkid_tag head = NULL;
101 DBG(printf(" adding tag %s=%s to cache\n", tag->bit_name, tag->bit_val));
103 if (!(head = blkid_find_head_cache(cache, tag))) {
104 head = blkid_new_tag();
106 return -BLKID_ERR_MEM;
108 DBG(printf(" creating new cache tag head %s\n",tag->bit_name));
109 head->bit_name = string_copy(tag->bit_name);
110 if (!head->bit_name) {
111 blkid_free_tag(head);
112 return -BLKID_ERR_MEM;
115 list_add_tail(&head->bit_tags, &cache->bic_tags);
118 /* Add this tag to global list */
119 list_add_tail(&tag->bit_names, &head->bit_names);
125 * Given a blkid device, return its name
127 extern const char *blkid_devname_name(blkid_dev dev)
129 return dev->bid_name;
133 * dev iteration routines for the public libblkid interface.
135 * These routines do not expose the list.h implementation, which are a
136 * contamination of the namespace, and which force us to reveal far, far
137 * too much of our internal implemenation. I'm not convinced I want
138 * to keep list.h in the long term, anyway. It's fine for kernel
139 * programming, but performance is not the #1 priority for this
140 * library, and I really don't like the tradeoff of type-safety for
141 * performance for this application. [tytso:20030125.2007EST]
145 * This series of functions iterate over all devices in a blkid cache
147 #define DEV_ITERATE_MAGIC 0x01a5284c
149 struct blkid_struct_dev_iterate {
155 extern blkid_dev_iterate blkid_dev_iterate_begin(blkid_cache cache)
157 blkid_dev_iterate iter;
159 iter = malloc(sizeof(struct blkid_struct_dev_iterate));
161 iter->magic = DEV_ITERATE_MAGIC;
163 iter->p = cache->bic_devs.next;
169 * Return 0 on success, -1 on error
171 extern int blkid_dev_next(blkid_dev_iterate iter,
175 if (!iter || iter->magic != DEV_ITERATE_MAGIC ||
176 iter->p == &iter->cache->bic_devs)
178 *dev = list_entry(iter->p, struct blkid_struct_dev, bid_devs);
179 iter->p = iter->p->next;
183 extern void blkid_dev_iterate_end(blkid_dev_iterate iter)
185 if (!iter || iter->magic != DEV_ITERATE_MAGIC)
192 * Add a device to the global cache list, along with all its tags.
194 blkid_dev blkid_add_dev_to_cache(blkid_cache cache, blkid_dev dev)
202 dev->bid_id = ++(cache->bic_idmax);
204 list_for_each(p, &cache->bic_devs) {
205 blkid_dev odev = list_entry(p, struct blkid_struct_dev, bid_devs);
206 int dup_uuid, dup_label, dup_name, dup_type;
208 dup_name = string_compare(odev->bid_name, dev->bid_name);
209 dup_label = string_compare(odev->bid_label, dev->bid_label);
210 dup_uuid = string_compare(odev->bid_uuid, dev->bid_uuid);
212 if (odev->bid_id == dev->bid_id)
213 dev->bid_id = ++(cache->bic_idmax);
215 /* Fields different, do nothing (check more fields?) */
216 if ((dup_name & SC_DIFF) && (dup_uuid & SC_DIFF) &&
217 (dup_label & SC_DIFF))
220 /* We can't simply allow duplicate fields if the bid_type is
221 * different, given that a filesystem may change from ext2
222 * to ext3 but it will have the same UUID and LABEL fields.
223 * We need to discard the old cache entry in this case.
226 /* If the UUIDs are the same but one is unverified discard it */
227 if (dup_uuid == SC_SAME) {
228 DBG(printf(" duplicate uuid %s\n", dev->bid_uuid));
229 if (!(odev->bid_flags & BLKID_BID_FL_VERIFIED)) {
230 dev->bid_id = odev->bid_id; /* keep old id */
231 blkid_free_dev(odev);
233 } else if (!(dev->bid_flags & BLKID_BID_FL_VERIFIED)) {
239 /* This shouldn't happen */
240 fprintf(stderr, "blkid: same UUID for %s and %s\n",
241 dev->bid_name, odev->bid_name);
244 /* If the device name is the same, discard one of them
245 * (prefer one that has been validated, or the first one).
247 if (dup_name == SC_SAME) {
248 DBG(printf(" duplicate devname %s\n", dev->bid_name));
249 if (odev->bid_flags & BLKID_BID_FL_VERIFIED ||
250 !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) {
251 if ((dup_uuid & SC_SAME) &&
252 (dup_label & SC_SAME)) /* use old id */
253 dev->bid_id = odev->bid_id;
258 blkid_free_dev(odev);
263 dup_type = string_compare(odev->bid_type, dev->bid_type);
265 if (dup_label == SC_SAME && dup_type == SC_SAME) {
266 DBG(printf(" duplicate label %s\n", dev->bid_label));
267 if (!(odev->bid_flags & BLKID_BID_FL_VERIFIED)) {
268 blkid_free_dev(odev);
270 } else if (!(dev->bid_flags & BLKID_BID_FL_VERIFIED)) {
275 fprintf(stderr, "blkid: same LABEL for %s and %s\n",
276 dev->bid_name, odev->bid_name);
281 DBG(printf(" adding new devname %s to cache\n", dev->bid_name));
283 cache->bic_flags |= BLKID_BIC_FL_CHANGED;
285 list_add_tail(&dev->bid_devs, &cache->bic_devs);
286 list_for_each(p, &dev->bid_tags) {
287 blkid_tag tag = list_entry(p, struct blkid_struct_tag,
289 add_tag_to_cache(cache, tag);
294 DBG(printf(" using old devname %s from cache\n", dev->bid_name));
299 int main(int argc, char** argv)
302 blkid_dev dev, newdev;
305 fprintf(stderr, "Usage:\t%s dev1 dev2\n"
306 "Test that adding the same device to the cache fails\n",
311 cache = blkid_new_cache();
316 dev = blkid_devname_to_dev(argv[1], 0);
317 newdev = blkid_add_dev_to_cache(cache, dev);
319 printf("devices changed for %s (unexpected)\n", argv[1]);
320 dev = blkid_devname_to_dev(argv[2], 0);
321 newdev = blkid_add_dev_to_cache(cache, dev);
323 printf("devices changed for %s (unexpected)\n", argv[2]);
324 dev = blkid_devname_to_dev(argv[2], 0);
325 newdev = blkid_add_dev_to_cache(cache, dev);
327 printf("devices changed for %s (expected)\n", argv[2]);
329 blkid_free_cache(cache);