tag.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * tag.c - allocation/initialization/free routines for tag structs
  4. *
  5. * Copyright (C) 2001 Andreas Dilger
  6. * Copyright (C) 2003 Theodore Ts'o
  7. *
  8. * %Begin-Header%
  9. * This file may be redistributed under the terms of the
  10. * GNU Lesser General Public License.
  11. * %End-Header%
  12. */
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <stdio.h>
  16. #include "blkidP.h"
  17. static blkid_tag blkid_new_tag(void)
  18. {
  19. blkid_tag tag;
  20. if (!(tag = (blkid_tag) calloc(1, sizeof(struct blkid_struct_tag))))
  21. return NULL;
  22. INIT_LIST_HEAD(&tag->bit_tags);
  23. INIT_LIST_HEAD(&tag->bit_names);
  24. return tag;
  25. }
  26. #ifdef CONFIG_BLKID_DEBUG
  27. void blkid_debug_dump_tag(blkid_tag tag)
  28. {
  29. if (!tag) {
  30. printf(" tag: NULL\n");
  31. return;
  32. }
  33. printf(" tag: %s=\"%s\"\n", tag->bit_name, tag->bit_val);
  34. }
  35. #endif
  36. void blkid_free_tag(blkid_tag tag)
  37. {
  38. if (!tag)
  39. return;
  40. DBG(DEBUG_TAG, printf(" freeing tag %s=%s\n", tag->bit_name,
  41. tag->bit_val ? tag->bit_val : "(NULL)"));
  42. DBG(DEBUG_TAG, blkid_debug_dump_tag(tag));
  43. list_del(&tag->bit_tags); /* list of tags for this device */
  44. list_del(&tag->bit_names); /* list of tags with this type */
  45. free(tag->bit_name);
  46. free(tag->bit_val);
  47. free(tag);
  48. }
  49. /*
  50. * Find the desired tag on a device. If value is NULL, then the
  51. * first such tag is returned, otherwise return only exact tag if found.
  52. */
  53. blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type)
  54. {
  55. struct list_head *p;
  56. if (!dev || !type)
  57. return NULL;
  58. list_for_each(p, &dev->bid_tags) {
  59. blkid_tag tmp = list_entry(p, struct blkid_struct_tag,
  60. bit_tags);
  61. if (!strcmp(tmp->bit_name, type))
  62. return tmp;
  63. }
  64. return NULL;
  65. }
  66. /*
  67. * Find the desired tag type in the cache.
  68. * We return the head tag for this tag type.
  69. */
  70. static blkid_tag blkid_find_head_cache(blkid_cache cache, const char *type)
  71. {
  72. blkid_tag head = NULL, tmp;
  73. struct list_head *p;
  74. if (!cache || !type)
  75. return NULL;
  76. list_for_each(p, &cache->bic_tags) {
  77. tmp = list_entry(p, struct blkid_struct_tag, bit_tags);
  78. if (!strcmp(tmp->bit_name, type)) {
  79. DBG(DEBUG_TAG,
  80. printf(" found cache tag head %s\n", type));
  81. head = tmp;
  82. break;
  83. }
  84. }
  85. return head;
  86. }
  87. /*
  88. * Set a tag on an existing device.
  89. *
  90. * If value is NULL, then delete the tagsfrom the device.
  91. */
  92. int blkid_set_tag(blkid_dev dev, const char *name,
  93. const char *value, const int vlength)
  94. {
  95. blkid_tag t = 0, head = 0;
  96. char *val = 0;
  97. if (!dev || !name)
  98. return -BLKID_ERR_PARAM;
  99. if (!(val = blkid_strndup(value, vlength)) && value)
  100. return -BLKID_ERR_MEM;
  101. t = blkid_find_tag_dev(dev, name);
  102. if (!value) {
  103. blkid_free_tag(t);
  104. } else if (t) {
  105. if (!strcmp(t->bit_val, val)) {
  106. /* Same thing, exit */
  107. free(val);
  108. return 0;
  109. }
  110. free(t->bit_val);
  111. t->bit_val = val;
  112. } else {
  113. /* Existing tag not present, add to device */
  114. if (!(t = blkid_new_tag()))
  115. goto errout;
  116. t->bit_name = blkid_strdup(name);
  117. t->bit_val = val;
  118. t->bit_dev = dev;
  119. list_add_tail(&t->bit_tags, &dev->bid_tags);
  120. if (dev->bid_cache) {
  121. head = blkid_find_head_cache(dev->bid_cache,
  122. t->bit_name);
  123. if (!head) {
  124. head = blkid_new_tag();
  125. if (!head)
  126. goto errout;
  127. DBG(DEBUG_TAG,
  128. printf(" creating new cache tag head %s\n", name));
  129. head->bit_name = blkid_strdup(name);
  130. if (!head->bit_name)
  131. goto errout;
  132. list_add_tail(&head->bit_tags,
  133. &dev->bid_cache->bic_tags);
  134. }
  135. list_add_tail(&t->bit_names, &head->bit_names);
  136. }
  137. }
  138. /* Link common tags directly to the device struct */
  139. if (!strcmp(name, "TYPE"))
  140. dev->bid_type = val;
  141. else if (!strcmp(name, "LABEL"))
  142. dev->bid_label = val;
  143. else if (!strcmp(name, "UUID"))
  144. dev->bid_uuid = val;
  145. if (dev->bid_cache)
  146. dev->bid_cache->bic_flags |= BLKID_BIC_FL_CHANGED;
  147. return 0;
  148. errout:
  149. blkid_free_tag(t);
  150. if (!t)
  151. free(val);
  152. blkid_free_tag(head);
  153. return -BLKID_ERR_MEM;
  154. }
  155. /*
  156. * Parse a "NAME=value" string. This is slightly different than
  157. * parse_token, because that will end an unquoted value at a space, while
  158. * this will assume that an unquoted value is the rest of the token (e.g.
  159. * if we are passed an already quoted string from the command-line we don't
  160. * have to both quote and escape quote so that the quotes make it to
  161. * us).
  162. *
  163. * Returns 0 on success, and -1 on failure.
  164. */
  165. int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val)
  166. {
  167. char *name, *value, *cp;
  168. DBG(DEBUG_TAG, printf("trying to parse '%s' as a tag\n", token));
  169. if (!token || !(cp = strchr(token, '=')))
  170. return -1;
  171. name = blkid_strdup(token);
  172. if (!name)
  173. return -1;
  174. value = name + (cp - token);
  175. *value++ = '\0';
  176. if (*value == '"' || *value == '\'') {
  177. char c = *value++;
  178. if (!(cp = strrchr(value, c)))
  179. goto errout; /* missing closing quote */
  180. *cp = '\0';
  181. }
  182. value = blkid_strdup(value);
  183. if (!value)
  184. goto errout;
  185. *ret_type = name;
  186. *ret_val = value;
  187. return 0;
  188. errout:
  189. free(name);
  190. return -1;
  191. }
  192. /*
  193. * Tag iteration routines for the public libblkid interface.
  194. *
  195. * These routines do not expose the list.h implementation, which are a
  196. * contamination of the namespace, and which force us to reveal far, far
  197. * too much of our internal implemenation. I'm not convinced I want
  198. * to keep list.h in the long term, anyway. It's fine for kernel
  199. * programming, but performance is not the #1 priority for this
  200. * library, and I really don't like the tradeoff of type-safety for
  201. * performance for this application. [tytso:20030125.2007EST]
  202. */
  203. /*
  204. * This series of functions iterate over all tags in a device
  205. */
  206. #define TAG_ITERATE_MAGIC 0x01a5284c
  207. struct blkid_struct_tag_iterate {
  208. int magic;
  209. blkid_dev dev;
  210. struct list_head *p;
  211. };
  212. blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev)
  213. {
  214. blkid_tag_iterate iter;
  215. iter = xmalloc(sizeof(struct blkid_struct_tag_iterate));
  216. iter->magic = TAG_ITERATE_MAGIC;
  217. iter->dev = dev;
  218. iter->p = dev->bid_tags.next;
  219. return iter;
  220. }
  221. /*
  222. * Return 0 on success, -1 on error
  223. */
  224. extern int blkid_tag_next(blkid_tag_iterate iter,
  225. const char **type, const char **value)
  226. {
  227. blkid_tag tag;
  228. *type = 0;
  229. *value = 0;
  230. if (!iter || iter->magic != TAG_ITERATE_MAGIC ||
  231. iter->p == &iter->dev->bid_tags)
  232. return -1;
  233. tag = list_entry(iter->p, struct blkid_struct_tag, bit_tags);
  234. *type = tag->bit_name;
  235. *value = tag->bit_val;
  236. iter->p = iter->p->next;
  237. return 0;
  238. }
  239. void blkid_tag_iterate_end(blkid_tag_iterate iter)
  240. {
  241. if (!iter || iter->magic != TAG_ITERATE_MAGIC)
  242. return;
  243. iter->magic = 0;
  244. free(iter);
  245. }
  246. /*
  247. * This function returns a device which matches a particular
  248. * type/value pair. If there is more than one device that matches the
  249. * search specification, it returns the one with the highest priority
  250. * value. This allows us to give preference to EVMS or LVM devices.
  251. *
  252. * XXX there should also be an interface which uses an iterator so we
  253. * can get all of the devices which match a type/value search parameter.
  254. */
  255. extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
  256. const char *type,
  257. const char *value)
  258. {
  259. blkid_tag head;
  260. blkid_dev dev;
  261. int pri;
  262. struct list_head *p;
  263. if (!cache || !type || !value)
  264. return NULL;
  265. blkid_read_cache(cache);
  266. DBG(DEBUG_TAG, printf("looking for %s=%s in cache\n", type, value));
  267. try_again:
  268. pri = -1;
  269. dev = 0;
  270. head = blkid_find_head_cache(cache, type);
  271. if (head) {
  272. list_for_each(p, &head->bit_names) {
  273. blkid_tag tmp = list_entry(p, struct blkid_struct_tag,
  274. bit_names);
  275. if (!strcmp(tmp->bit_val, value) &&
  276. tmp->bit_dev->bid_pri > pri) {
  277. dev = tmp->bit_dev;
  278. pri = dev->bid_pri;
  279. }
  280. }
  281. }
  282. if (dev && !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) {
  283. dev = blkid_verify(cache, dev);
  284. if (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED))
  285. goto try_again;
  286. }
  287. if (!dev && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) {
  288. if (blkid_probe_all(cache) < 0)
  289. return NULL;
  290. goto try_again;
  291. }
  292. return dev;
  293. }
  294. #ifdef TEST_PROGRAM
  295. #ifdef HAVE_GETOPT_H
  296. #include <getopt.h>
  297. #else
  298. extern char *optarg;
  299. extern int optind;
  300. #endif
  301. void usage(char *prog)
  302. {
  303. fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask] device "
  304. "[type value]\n",
  305. prog);
  306. fprintf(stderr, "\tList all tags for a device and exit\n", prog);
  307. exit(1);
  308. }
  309. int main(int argc, char **argv)
  310. {
  311. blkid_tag_iterate iter;
  312. blkid_cache cache = NULL;
  313. blkid_dev dev;
  314. int c, ret, found;
  315. int flags = BLKID_DEV_FIND;
  316. char *tmp;
  317. char *file = NULL;
  318. char *devname = NULL;
  319. char *search_type = NULL;
  320. char *search_value = NULL;
  321. const char *type, *value;
  322. while ((c = getopt (argc, argv, "m:f:")) != EOF)
  323. switch (c) {
  324. case 'f':
  325. file = optarg;
  326. break;
  327. case 'm':
  328. blkid_debug_mask = strtoul (optarg, &tmp, 0);
  329. if (*tmp) {
  330. fprintf(stderr, "Invalid debug mask: %d\n",
  331. optarg);
  332. exit(1);
  333. }
  334. break;
  335. case '?':
  336. usage(argv[0]);
  337. }
  338. if (argc > optind)
  339. devname = argv[optind++];
  340. if (argc > optind)
  341. search_type = argv[optind++];
  342. if (argc > optind)
  343. search_value = argv[optind++];
  344. if (!devname || (argc != optind))
  345. usage(argv[0]);
  346. if ((ret = blkid_get_cache(&cache, file)) != 0) {
  347. fprintf(stderr, "%s: error creating cache (%d)\n",
  348. argv[0], ret);
  349. exit(1);
  350. }
  351. dev = blkid_get_dev(cache, devname, flags);
  352. if (!dev) {
  353. fprintf(stderr, "%s: cannot find device in blkid cache\n");
  354. exit(1);
  355. }
  356. if (search_type) {
  357. found = blkid_dev_has_tag(dev, search_type, search_value);
  358. printf("Device %s: (%s, %s) %s\n", blkid_dev_devname(dev),
  359. search_type, search_value ? search_value : "NULL",
  360. found ? "FOUND" : "NOT FOUND");
  361. return !found;
  362. }
  363. printf("Device %s...\n", blkid_dev_devname(dev));
  364. iter = blkid_tag_iterate_begin(dev);
  365. while (blkid_tag_next(iter, &type, &value) == 0) {
  366. printf("\tTag %s has value %s\n", type, value);
  367. }
  368. blkid_tag_iterate_end(iter);
  369. blkid_put_cache(cache);
  370. return 0;
  371. }
  372. #endif