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