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