tag.c revision b697f9d01c5f07842426f7d8e918bf3110028662
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