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