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