Home | History | Annotate | Download | only in blkid
      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 
     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
     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 
     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  */
     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 
     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  */
    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  */
    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  */
    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 
    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  */
    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 
    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  */
    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 
    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 
    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