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