tag.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  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. #include <stdlib.h>
  13. #include <string.h>
  14. #include <stdio.h>
  15. #include "blkidP.h"
  16. static blkid_tag blkid_new_tag(void)
  17. {
  18. blkid_tag tag;
  19. if (!(tag = (blkid_tag) calloc(1, sizeof(struct blkid_struct_tag))))
  20. return NULL;
  21. INIT_LIST_HEAD(&tag->bit_tags);
  22. INIT_LIST_HEAD(&tag->bit_names);
  23. return tag;
  24. }
  25. void blkid_free_tag(blkid_tag tag)
  26. {
  27. if (!tag)
  28. return;
  29. DBG(DEBUG_TAG, printf(" freeing tag %s=%s\n", tag->bit_name,
  30. tag->bit_val ? tag->bit_val : "(NULL)"));
  31. DEB_DUMP_TAG(DEBUG_TAG, tag);
  32. list_del(&tag->bit_tags); /* list of tags for this device */
  33. list_del(&tag->bit_names); /* list of tags with this type */
  34. if (tag->bit_name)
  35. free(tag->bit_name);
  36. if (tag->bit_val)
  37. free(tag->bit_val);
  38. free(tag);
  39. }
  40. /*
  41. * Find the desired tag on a device. If value is NULL, then the
  42. * first such tag is returned, otherwise return only exact tag if found.
  43. */
  44. blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type)
  45. {
  46. struct list_head *p;
  47. if (!dev || !type)
  48. return NULL;
  49. list_for_each(p, &dev->bid_tags) {
  50. blkid_tag tmp = list_entry(p, struct blkid_struct_tag,
  51. bit_tags);
  52. if (!strcmp(tmp->bit_name, type))
  53. return tmp;
  54. }
  55. return NULL;
  56. }
  57. /*
  58. * Find the desired tag type in the cache.
  59. * We return the head tag for this tag type.
  60. */
  61. static blkid_tag blkid_find_head_cache(blkid_cache cache, const char *type)
  62. {
  63. blkid_tag head = NULL, tmp;
  64. struct list_head *p;
  65. if (!cache || !type)
  66. return NULL;
  67. list_for_each(p, &cache->bic_tags) {
  68. tmp = list_entry(p, struct blkid_struct_tag, bit_tags);
  69. if (!strcmp(tmp->bit_name, type)) {
  70. DBG(DEBUG_TAG,
  71. printf(" found cache tag head %s\n", type));
  72. head = tmp;
  73. break;
  74. }
  75. }
  76. return head;
  77. }
  78. /*
  79. * Set a tag on an existing device.
  80. *
  81. * If value is NULL, then delete the tagsfrom the device.
  82. */
  83. int blkid_set_tag(blkid_dev dev, const char *name,
  84. const char *value, const int vlength)
  85. {
  86. blkid_tag t = 0, head = 0;
  87. char *val = 0;
  88. if (!dev || !name)
  89. return -BLKID_ERR_PARAM;
  90. if (!(val = blkid_strndup(value, vlength)) && value)
  91. return -BLKID_ERR_MEM;
  92. t = blkid_find_tag_dev(dev, name);
  93. if (!value) {
  94. if (t)
  95. blkid_free_tag(t);
  96. } else if (t) {
  97. if (!strcmp(t->bit_val, val)) {
  98. /* Same thing, exit */
  99. free(val);
  100. return 0;
  101. }
  102. free(t->bit_val);
  103. t->bit_val = val;
  104. } else {
  105. /* Existing tag not present, add to device */
  106. if (!(t = blkid_new_tag()))
  107. goto errout;
  108. t->bit_name = blkid_strdup(name);
  109. t->bit_val = val;
  110. t->bit_dev = dev;
  111. list_add_tail(&t->bit_tags, &dev->bid_tags);
  112. if (dev->bid_cache) {
  113. head = blkid_find_head_cache(dev->bid_cache,
  114. t->bit_name);
  115. if (!head) {
  116. head = blkid_new_tag();
  117. if (!head)
  118. goto errout;
  119. DBG(DEBUG_TAG,
  120. printf(" creating new cache tag head %s\n", name));
  121. head->bit_name = blkid_strdup(name);
  122. if (!head->bit_name)
  123. goto errout;
  124. list_add_tail(&head->bit_tags,
  125. &dev->bid_cache->bic_tags);
  126. }
  127. list_add_tail(&t->bit_names, &head->bit_names);
  128. }
  129. }
  130. /* Link common tags directly to the device struct */
  131. if (!strcmp(name, "TYPE"))
  132. dev->bid_type = val;
  133. else if (!strcmp(name, "LABEL"))
  134. dev->bid_label = val;
  135. else if (!strcmp(name, "UUID"))
  136. dev->bid_uuid = val;
  137. if (dev->bid_cache)
  138. dev->bid_cache->bic_flags |= BLKID_BIC_FL_CHANGED;
  139. return 0;
  140. errout:
  141. if (t)
  142. blkid_free_tag(t);
  143. else if (val)
  144. free(val);
  145. if (head)
  146. blkid_free_tag(head);
  147. return -BLKID_ERR_MEM;
  148. }
  149. /*
  150. * Parse a "NAME=value" string. This is slightly different than
  151. * parse_token, because that will end an unquoted value at a space, while
  152. * this will assume that an unquoted value is the rest of the token (e.g.
  153. * if we are passed an already quoted string from the command-line we don't
  154. * have to both quote and escape quote so that the quotes make it to
  155. * us).
  156. *
  157. * Returns 0 on success, and -1 on failure.
  158. */
  159. int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val)
  160. {
  161. char *name, *value, *cp;
  162. DBG(DEBUG_TAG, printf("trying to parse '%s' as a tag\n", token));
  163. if (!token || !(cp = strchr(token, '=')))
  164. return -1;
  165. name = blkid_strdup(token);
  166. if (!name)
  167. return -1;
  168. value = name + (cp - token);
  169. *value++ = '\0';
  170. if (*value == '"' || *value == '\'') {
  171. char c = *value++;
  172. if (!(cp = strrchr(value, c)))
  173. goto errout; /* missing closing quote */
  174. *cp = '\0';
  175. }
  176. value = blkid_strdup(value);
  177. if (!value)
  178. goto errout;
  179. *ret_type = name;
  180. *ret_val = value;
  181. return 0;
  182. errout:
  183. free(name);
  184. return -1;
  185. }
  186. /*
  187. * Tag iteration routines for the public libblkid interface.
  188. *
  189. * These routines do not expose the list.h implementation, which are a
  190. * contamination of the namespace, and which force us to reveal far, far
  191. * too much of our internal implemenation. I'm not convinced I want
  192. * to keep list.h in the long term, anyway. It's fine for kernel
  193. * programming, but performance is not the #1 priority for this
  194. * library, and I really don't like the tradeoff of type-safety for
  195. * performance for this application. [tytso:20030125.2007EST]
  196. */
  197. /*
  198. * This series of functions iterate over all tags in a device
  199. */
  200. #define TAG_ITERATE_MAGIC 0x01a5284c
  201. struct blkid_struct_tag_iterate {
  202. int magic;
  203. blkid_dev dev;
  204. struct list_head *p;
  205. };
  206. extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev)
  207. {
  208. blkid_tag_iterate iter;
  209. iter = xmalloc(sizeof(struct blkid_struct_tag_iterate));
  210. iter->magic = TAG_ITERATE_MAGIC;
  211. iter->dev = dev;
  212. iter->p = dev->bid_tags.next;
  213. return (iter);
  214. }
  215. /*
  216. * Return 0 on success, -1 on error
  217. */
  218. extern int blkid_tag_next(blkid_tag_iterate iter,
  219. const char **type, const char **value)
  220. {
  221. blkid_tag tag;
  222. *type = 0;
  223. *value = 0;
  224. if (!iter || iter->magic != TAG_ITERATE_MAGIC ||
  225. iter->p == &iter->dev->bid_tags)
  226. return -1;
  227. tag = list_entry(iter->p, struct blkid_struct_tag, bit_tags);
  228. *type = tag->bit_name;
  229. *value = tag->bit_val;
  230. iter->p = iter->p->next;
  231. return 0;
  232. }
  233. extern void blkid_tag_iterate_end(blkid_tag_iterate iter)
  234. {
  235. if (!iter || iter->magic != TAG_ITERATE_MAGIC)
  236. return;
  237. iter->magic = 0;
  238. free(iter);
  239. }
  240. /*
  241. * This function returns a device which matches a particular
  242. * type/value pair. If there is more than one device that matches the
  243. * search specification, it returns the one with the highest priority
  244. * value. This allows us to give preference to EVMS or LVM devices.
  245. *
  246. * XXX there should also be an interface which uses an iterator so we
  247. * can get all of the devices which match a type/value search parameter.
  248. */
  249. extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
  250. const char *type,
  251. const char *value)
  252. {
  253. blkid_tag head;
  254. blkid_dev dev;
  255. int pri;
  256. struct list_head *p;
  257. if (!cache || !type || !value)
  258. return NULL;
  259. blkid_read_cache(cache);
  260. DBG(DEBUG_TAG, printf("looking for %s=%s in cache\n", type, value));
  261. try_again:
  262. pri = -1;
  263. dev = 0;
  264. head = blkid_find_head_cache(cache, type);
  265. if (head) {
  266. list_for_each(p, &head->bit_names) {
  267. blkid_tag tmp = list_entry(p, struct blkid_struct_tag,
  268. bit_names);
  269. if (!strcmp(tmp->bit_val, value) &&
  270. tmp->bit_dev->bid_pri > pri) {
  271. dev = tmp->bit_dev;
  272. pri = dev->bid_pri;
  273. }
  274. }
  275. }
  276. if (dev && !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) {
  277. dev = blkid_verify(cache, dev);
  278. if (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED))
  279. goto try_again;
  280. }
  281. if (!dev && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) {
  282. if (blkid_probe_all(cache) < 0)
  283. return NULL;
  284. goto try_again;
  285. }
  286. return dev;
  287. }