Whamcloud - gitweb
tag.c (blkid_set_tag): Fix bug; don't return an error when
[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 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 = malloc(sizeof(struct blkid_struct_tag_iterate));
250         if (iter) {
251                 iter->magic = TAG_ITERATE_MAGIC;
252                 iter->dev = dev;
253                 iter->p = dev->bid_tags.next;
254         }
255         return (iter);
256 }
257
258 /*
259  * Return 0 on success, -1 on error
260  */
261 extern int blkid_tag_next(blkid_tag_iterate iter,
262                           const char **type, const char **value)
263 {
264         blkid_tag tag;
265         
266         *type = 0;
267         *value = 0;
268         if (!iter || iter->magic != TAG_ITERATE_MAGIC ||
269             iter->p == &iter->dev->bid_tags)
270                 return -1;
271         tag = list_entry(iter->p, struct blkid_struct_tag, bit_tags);
272         *type = tag->bit_name;
273         *value = tag->bit_val;
274         iter->p = iter->p->next;
275         return 0;
276 }
277
278 extern void blkid_tag_iterate_end(blkid_tag_iterate iter)
279 {
280         if (!iter || iter->magic != TAG_ITERATE_MAGIC)
281                 return;
282         iter->magic = 0;
283         free(iter);
284 }
285
286 /*
287  * This function returns a device which matches a particular
288  * type/value pair.  If there is more than one device that matches the
289  * search specification, it returns the one with the highest priority
290  * value.  This allows us to give preference to EVMS or LVM devices.
291  *
292  * XXX there should also be an interface which uses an iterator so we
293  * can get all of the devices which match a type/value search parameter.
294  */
295 extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
296                                          const char *type,
297                                          const char *value)
298 {
299         blkid_tag       head;
300         blkid_dev       dev;
301         int             pri;
302         struct list_head *p;
303
304         if (!cache || !type || !value)
305                 return NULL;
306
307         blkid_read_cache(cache);
308         
309         DBG(DEBUG_TAG, printf("looking for %s=%s in cache\n", type, value));
310         
311 try_again:
312         pri = -1;
313         dev = 0;
314         head = blkid_find_head_cache(cache, type);
315
316         if (head) {
317                 list_for_each(p, &head->bit_names) {
318                         blkid_tag tmp = list_entry(p, struct blkid_struct_tag, 
319                                                    bit_names);
320
321                         if (!strcmp(tmp->bit_val, value) &&
322                             tmp->bit_dev->bid_pri > pri) {
323                                 dev = tmp->bit_dev;
324                                 pri = dev->bid_pri;
325                         }
326                 }
327         }
328         if (dev && !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) {
329                 dev = blkid_verify_devname(cache, dev);
330                 if (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED))
331                         goto try_again;
332         }
333
334         if (!dev && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) {
335                 blkid_probe_all(cache);
336                 goto try_again;
337         }
338         return dev;
339 }