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