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