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