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