source: branches/2.2.5/mindi-busybox/e2fsprogs/old_e2fsprogs/blkid/tag.c @ 1765

Last change on this file since 1765 was 1765, checked in by Bruno Cornec, 13 years ago

Update to busybox 1.7.2

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