Whamcloud - gitweb
3948a1e6d6d12563e17a0be532b03fb88653659c
[tools/e2fsprogs.git] / lib / blkid / tag.c
1 /*
2  * tag.c - allocation/initialization/free routines for tag structs
3  *
4  * Copyright (C) 2001 Andreas Dilger
5  * Copyright (C) 2003 Theodore Ts'o
6  *
7  * %Begin-Header%
8  * This file may be redistributed under the terms of the
9  * GNU Lesser General Public License.
10  * %End-Header%
11  */
12
13 #include <stdlib.h>
14 #include <string.h>
15 #include <stdio.h>
16
17 #include "blkidP.h"
18
19 #ifdef DEBUG_TAG
20 #define DBG(x)  x
21 #else
22 #define DBG(x)
23 #endif
24
25 static blkid_tag blkid_new_tag(void)
26 {
27         blkid_tag tag;
28
29         if (!(tag = (blkid_tag) calloc(1, sizeof(struct blkid_struct_tag))))
30                 return NULL;
31
32         INIT_LIST_HEAD(&tag->bit_tags);
33         INIT_LIST_HEAD(&tag->bit_names);
34
35         return tag;
36 }
37
38 void blkid_free_tag(blkid_tag tag)
39 {
40         if (!tag)
41                 return;
42
43         DBG(printf("    freeing tag %s=%s\n", tag->bit_name,
44                    tag->bit_val ? tag->bit_val : "(NULL)"));
45         DEB_DUMP_TAG(tag);
46
47         list_del(&tag->bit_tags);       /* list of tags for this device */
48         list_del(&tag->bit_names);      /* list of tags with this type */
49
50         if (tag->bit_name)
51                 free(tag->bit_name);
52         if (tag->bit_val)
53                 free(tag->bit_val);
54
55         free(tag);
56 }
57
58 /*
59  * Find the desired tag on a device.  If value is NULL, then the
60  * first such tag is returned, otherwise return only exact tag if found.
61  */
62 blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type)
63 {
64         struct list_head *p;
65
66         if (!dev || !type)
67                 return NULL;
68
69         list_for_each(p, &dev->bid_tags) {
70                 blkid_tag tmp = list_entry(p, struct blkid_struct_tag,
71                                            bit_tags);
72
73                 if (!strcmp(tmp->bit_name, type))
74                         return tmp;
75         }
76         return NULL;
77 }
78
79 /*
80  * Find the desired tag type in the cache.
81  * We return the head tag for this tag type.
82  */
83 static blkid_tag blkid_find_head_cache(blkid_cache cache, const char *type)
84 {
85         blkid_tag head = NULL, tmp;
86         struct list_head *p;
87
88         if (!cache || !type)
89                 return NULL;
90
91         list_for_each(p, &cache->bic_tags) {
92                 tmp = list_entry(p, struct blkid_struct_tag, bit_tags);
93                 if (!strcmp(tmp->bit_name, type)) {
94                         DBG(printf("    found cache tag head %s\n", type));
95                         head = tmp;
96                         break;
97                 }
98         }
99         return head;
100 }
101
102 /*
103  * Set a tag on an existing device.
104  * 
105  * If replace is non-zero, blkid_set_tag() will replace the existing
106  * tag with the specified value.  Otherwise, it will add the specified
107  * tag to the device.
108  *
109  * If value is NULL, then delete all tags with that name from the
110  * device.
111  */
112 int blkid_set_tag(blkid_dev dev, const char *name,
113                   const char *value, const int vlength, int replace)
114 {
115         blkid_tag       t = 0, head = 0;
116         char            *val = 0;
117
118         if (!dev || !name)
119                 return -BLKID_ERR_PARAM;
120
121 repeat:
122         t = blkid_find_tag_dev(dev, name);
123         val = blkid_strndup(value, vlength);
124         if (!value) {
125                 if (t) {
126                         blkid_free_tag(t);
127                         goto repeat;
128                 } else
129                         goto link_tags;
130         }
131         if (!val)
132                 goto errout;
133         if (t) {
134                 if (!strcmp(t->bit_val, val)) {
135                         /* Same thing, exit */
136                         free(val);
137                         return 0;
138                 }
139                 if (replace) {
140                         free(t->bit_val);
141                         t->bit_val = val;
142                         goto link_tags;
143                 }
144                 dev->bid_flags |= BLKID_BID_FL_MTYPE;
145         }
146
147         /* Existing tag not present, add to device */
148         t = blkid_new_tag();
149         if (!t)
150                 goto errout;
151         t->bit_name = blkid_strdup(name);
152         t->bit_val = val;
153         t->bit_dev = dev;
154
155         list_add_tail(&t->bit_tags, &dev->bid_tags);
156                 
157         if (dev->bid_cache) {
158                 head = blkid_find_head_cache(dev->bid_cache, t->bit_name);
159                 if (!head) {
160                         head = blkid_new_tag();
161                         if (!head)
162                                 goto errout;
163
164                         DBG(printf("    creating new cache tag head %s\n",
165                                    name));
166                         head->bit_name = blkid_strdup(name);
167                         if (!head->bit_name)
168                                 goto errout;
169                         list_add_tail(&head->bit_tags,
170                                       &dev->bid_cache->bic_tags);
171                 }
172                 list_add_tail(&t->bit_names, &head->bit_names);
173         }
174         
175 link_tags:
176         /* Link common tags directly to the device struct */
177         if (!strcmp(name, "TYPE") && (!val || !dev->bid_type))
178                 dev->bid_type = val;
179         else if (!strcmp(name, "LABEL"))
180                 dev->bid_label = val;
181         else if (!strcmp(name, "UUID"))
182                 dev->bid_uuid = val;
183                 
184         if (dev->bid_cache)
185                 dev->bid_cache->bic_flags |= BLKID_BIC_FL_CHANGED;
186         return 0;
187
188 errout:
189         if (t)
190                 blkid_free_tag(t);
191         else if (val)
192                 free(val);
193         if (head)
194                 blkid_free_tag(head);
195         return -BLKID_ERR_MEM;
196 }
197
198
199 /*
200  * Parse a "NAME=value" string.  This is slightly different than
201  * parse_token, because that will end an unquoted value at a space, while
202  * this will assume that an unquoted value is the rest of the token (e.g.
203  * if we are passed an already quoted string from the command-line we don't
204  * have to both quote and escape quote so that the quotes make it to
205  * us).
206  *
207  * Returns 0 on success, and -1 on failure.
208  */
209 int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val)
210 {
211         char *name, *value, *cp;
212
213         DBG(printf("trying to parse '%s' as a tag\n", token));
214
215         if (!token || !(cp = strchr(token, '=')))
216                 return -1;
217
218         name = blkid_strdup(token);
219         if (!name)
220                 return -1;
221         value = name + (cp - token);
222         *value++ = '\0';
223         if (*value == '"' || *value == '\'') {
224                 char c = *value++;
225                 if (!(cp = strrchr(value, c)))
226                         goto errout; /* missing closing quote */
227                 *cp = '\0';
228         }
229         value = blkid_strdup(value);
230         if (!value)
231                 goto errout;
232
233         *ret_type = name;
234         *ret_val = value;
235
236         return 0;
237
238 errout:
239         free(name);
240         return -1;
241 }
242
243 /*
244  * Tag iteration routines for the public libblkid interface.
245  *
246  * These routines do not expose the list.h implementation, which are a
247  * contamination of the namespace, and which force us to reveal far, far
248  * too much of our internal implemenation.  I'm not convinced I want
249  * to keep list.h in the long term, anyway.  It's fine for kernel
250  * programming, but performance is not the #1 priority for this
251  * library, and I really don't like the tradeoff of type-safety for
252  * performance for this application.  [tytso:20030125.2007EST]
253  */
254
255 /*
256  * This series of functions iterate over all tags in a device
257  */
258 #define TAG_ITERATE_MAGIC       0x01a5284c
259         
260 struct blkid_struct_tag_iterate {
261         int                     magic;
262         blkid_dev               dev;
263         struct list_head        *p;
264 };
265
266 extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev)
267 {
268         blkid_tag_iterate       iter;
269
270         iter = malloc(sizeof(struct blkid_struct_tag_iterate));
271         if (iter) {
272                 iter->magic = TAG_ITERATE_MAGIC;
273                 iter->dev = dev;
274                 iter->p = dev->bid_tags.next;
275         }
276         return (iter);
277 }
278
279 /*
280  * Return 0 on success, -1 on error
281  */
282 extern int blkid_tag_next(blkid_tag_iterate iter,
283                           const char **type, const char **value)
284 {
285         blkid_tag tag;
286         
287         *type = 0;
288         *value = 0;
289         if (!iter || iter->magic != TAG_ITERATE_MAGIC ||
290             iter->p == &iter->dev->bid_tags)
291                 return -1;
292         tag = list_entry(iter->p, struct blkid_struct_tag, bit_tags);
293         *type = tag->bit_name;
294         *value = tag->bit_val;
295         iter->p = iter->p->next;
296         return 0;
297 }
298
299 extern void blkid_tag_iterate_end(blkid_tag_iterate iter)
300 {
301         if (!iter || iter->magic != TAG_ITERATE_MAGIC)
302                 return;
303         iter->magic = 0;
304         free(iter);
305 }
306
307 /*
308  * This function returns a device which matches a particular
309  * type/value pair.  If there is more than one device that matches the
310  * search specification, it returns the one with the highest priority
311  * value.  This allows us to give preference to EVMS or LVM devices.
312  *
313  * XXX there should also be an interface which uses an iterator so we
314  * can get all of the devices which match a type/value search parameter.
315  */
316 extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
317                                          const char *type,
318                                          const char *value)
319 {
320         blkid_tag       head, found;
321         blkid_dev       dev;
322         int             pri;
323         struct list_head *p;
324
325         if (!cache || !type || !value)
326                 return NULL;
327
328         DBG(printf("looking for %s=%s in cache\n", type, value));
329         
330 try_again:
331         pri = -1;
332         found = 0;
333         head = blkid_find_head_cache(cache, type);
334
335         if (head) {
336                 list_for_each(p, &head->bit_names) {
337                         blkid_tag tmp = list_entry(p, struct blkid_struct_tag, 
338                                                    bit_names);
339
340                         if (!strcmp(tmp->bit_val, value) &&
341                             tmp->bit_dev->bid_pri > pri) {
342                                 found = tmp;
343                                 dev = found->bit_dev;
344                                 pri = dev->bid_pri;
345                         }
346                 }
347         }
348         dev = blkid_verify_devname(cache, dev);
349         if (dev && strcmp(found->bit_val, value))
350                 dev = 0;
351
352         if ((!head || !dev) && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) {
353                 blkid_probe_all(cache);
354                 goto try_again;
355         }
356         return dev;
357 }