blob: 6fcaa7e5e30a5e2b838e0c78d7e85e3ef2a1d98b [file] [log] [blame]
bigbiff bigbiffe60683a2013-02-22 20:55:50 -05001/*
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
bigbiff bigbiffe60683a2013-02-22 20:55:50 -050033void blkid_debug_dump_tag(blkid_tag tag)
34{
35 if (!tag) {
bigbiff7b4c7a62015-01-01 19:44:14 -050036 fprintf(stderr, " tag: NULL\n");
bigbiff bigbiffe60683a2013-02-22 20:55:50 -050037 return;
38 }
39
bigbiff7b4c7a62015-01-01 19:44:14 -050040 fprintf(stderr, " tag: %s=\"%s\"\n", tag->bit_name, tag->bit_val);
bigbiff bigbiffe60683a2013-02-22 20:55:50 -050041}
bigbiff bigbiffe60683a2013-02-22 20:55:50 -050042
43void blkid_free_tag(blkid_tag tag)
44{
45 if (!tag)
46 return;
47
bigbiff7b4c7a62015-01-01 19:44:14 -050048 DBG(TAG, ul_debug(" freeing tag %s=%s", tag->bit_name,
bigbiff bigbiffe60683a2013-02-22 20:55:50 -050049 tag->bit_val ? tag->bit_val : "(NULL)"));
bigbiff7b4c7a62015-01-01 19:44:14 -050050 DBG(TAG, blkid_debug_dump_tag(tag));
bigbiff bigbiffe60683a2013-02-22 20:55:50 -050051
52 list_del(&tag->bit_tags); /* list of tags for this device */
53 list_del(&tag->bit_names); /* list of tags with this type */
54
55 free(tag->bit_name);
56 free(tag->bit_val);
57
58 free(tag);
59}
60
61/*
62 * Find the desired tag on a device. If value is NULL, then the
63 * first such tag is returned, otherwise return only exact tag if found.
64 */
65blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type)
66{
67 struct list_head *p;
68
bigbiff bigbiffe60683a2013-02-22 20:55:50 -050069 list_for_each(p, &dev->bid_tags) {
70 blkid_tag tmp = list_entry(p, struct blkid_struct_tag,
71 bit_tags);
72
73 if (!strcmp(tmp->bit_name, type))
74 return tmp;
75 }
76 return NULL;
77}
78
bigbiff7b4c7a62015-01-01 19:44:14 -050079int blkid_dev_has_tag(blkid_dev dev, const char *type,
bigbiff bigbiffe60683a2013-02-22 20:55:50 -050080 const char *value)
81{
82 blkid_tag tag;
83
84 tag = blkid_find_tag_dev(dev, type);
85 if (!value)
86 return (tag != NULL);
87 if (!tag || strcmp(tag->bit_val, value))
88 return 0;
89 return 1;
90}
91
92/*
93 * Find the desired tag type in the cache.
94 * We return the head tag for this tag type.
95 */
96static blkid_tag blkid_find_head_cache(blkid_cache cache, const char *type)
97{
98 blkid_tag head = NULL, tmp;
99 struct list_head *p;
100
101 if (!cache || !type)
102 return NULL;
103
104 list_for_each(p, &cache->bic_tags) {
105 tmp = list_entry(p, struct blkid_struct_tag, bit_tags);
106 if (!strcmp(tmp->bit_name, type)) {
bigbiff7b4c7a62015-01-01 19:44:14 -0500107 DBG(TAG, ul_debug(" found cache tag head %s", type));
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500108 head = tmp;
109 break;
110 }
111 }
112 return head;
113}
114
115/*
116 * Set a tag on an existing device.
117 *
118 * If value is NULL, then delete the tagsfrom the device.
119 */
120int blkid_set_tag(blkid_dev dev, const char *name,
121 const char *value, const int vlength)
122{
123 blkid_tag t = 0, head = 0;
124 char *val = 0;
125 char **dev_var = 0;
126
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500127 if (value && !(val = strndup(value, vlength)))
128 return -BLKID_ERR_MEM;
129
130 /*
131 * Certain common tags are linked directly to the device struct
132 * We need to know what they are before we do anything else because
133 * the function name parameter might get freed later on.
134 */
135 if (!strcmp(name, "TYPE"))
136 dev_var = &dev->bid_type;
137 else if (!strcmp(name, "LABEL"))
138 dev_var = &dev->bid_label;
139 else if (!strcmp(name, "UUID"))
140 dev_var = &dev->bid_uuid;
141
142 t = blkid_find_tag_dev(dev, name);
143 if (!value) {
144 if (t)
145 blkid_free_tag(t);
146 } else if (t) {
147 if (!strcmp(t->bit_val, val)) {
148 /* Same thing, exit */
149 free(val);
150 return 0;
151 }
152 free(t->bit_val);
153 t->bit_val = val;
154 } else {
155 /* Existing tag not present, add to device */
156 if (!(t = blkid_new_tag()))
157 goto errout;
Ethan Yonker34ae4832016-08-24 15:32:18 -0500158 t->bit_name = strdup(name);
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500159 t->bit_val = val;
160 t->bit_dev = dev;
161
162 list_add_tail(&t->bit_tags, &dev->bid_tags);
163
164 if (dev->bid_cache) {
165 head = blkid_find_head_cache(dev->bid_cache,
166 t->bit_name);
167 if (!head) {
168 head = blkid_new_tag();
169 if (!head)
170 goto errout;
171
bigbiff7b4c7a62015-01-01 19:44:14 -0500172 DBG(TAG, ul_debug(" creating new cache tag head %s", name));
Ethan Yonker34ae4832016-08-24 15:32:18 -0500173 head->bit_name = strdup(name);
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500174 if (!head->bit_name)
175 goto errout;
176 list_add_tail(&head->bit_tags,
177 &dev->bid_cache->bic_tags);
178 }
179 list_add_tail(&t->bit_names, &head->bit_names);
180 }
181 }
182
183 /* Link common tags directly to the device struct */
184 if (dev_var)
185 *dev_var = val;
186
187 if (dev->bid_cache)
188 dev->bid_cache->bic_flags |= BLKID_BIC_FL_CHANGED;
189 return 0;
190
191errout:
192 if (t)
193 blkid_free_tag(t);
194 else
195 free(val);
196 if (head)
197 blkid_free_tag(head);
198 return -BLKID_ERR_MEM;
199}
200
201
202/*
203 * Parse a "NAME=value" string. This is slightly different than
204 * parse_token, because that will end an unquoted value at a space, while
205 * this will assume that an unquoted value is the rest of the token (e.g.
206 * if we are passed an already quoted string from the command-line we don't
207 * have to both quote and escape quote so that the quotes make it to
208 * us).
209 *
210 * Returns 0 on success, and -1 on failure.
211 */
212int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val)
213{
214 char *name, *value, *cp;
215
bigbiff7b4c7a62015-01-01 19:44:14 -0500216 DBG(TAG, ul_debug("trying to parse '%s' as a tag", token));
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500217
218 if (!token || !(cp = strchr(token, '=')))
219 return -1;
220
221 name = strdup(token);
222 if (!name)
223 return -1;
224 value = name + (cp - token);
225 *value++ = '\0';
226 if (*value == '"' || *value == '\'') {
227 char c = *value++;
228 if (!(cp = strrchr(value, c)))
229 goto errout; /* missing closing quote */
230 *cp = '\0';
231 }
bigbiff7b4c7a62015-01-01 19:44:14 -0500232
233 if (ret_val) {
234 value = value && *value ? strdup(value) : NULL;
235 if (!value)
236 goto errout;
237 *ret_val = value;
238 }
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500239
240 if (ret_type)
241 *ret_type = name;
bigbiff7b4c7a62015-01-01 19:44:14 -0500242 else
243 free(name);
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500244
245 return 0;
246
247errout:
bigbiff7b4c7a62015-01-01 19:44:14 -0500248 DBG(TAG, ul_debug("parse error: '%s'", token));
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500249 free(name);
250 return -1;
251}
252
253/*
254 * Tag iteration routines for the public libblkid interface.
255 *
256 * These routines do not expose the list.h implementation, which are a
257 * contamination of the namespace, and which force us to reveal far, far
258 * too much of our internal implemenation. I'm not convinced I want
259 * to keep list.h in the long term, anyway. It's fine for kernel
260 * programming, but performance is not the #1 priority for this
261 * library, and I really don't like the tradeoff of type-safety for
262 * performance for this application. [tytso:20030125.2007EST]
263 */
264
265/*
266 * This series of functions iterate over all tags in a device
267 */
268#define TAG_ITERATE_MAGIC 0x01a5284c
269
270struct blkid_struct_tag_iterate {
271 int magic;
272 blkid_dev dev;
273 struct list_head *p;
274};
275
bigbiff7b4c7a62015-01-01 19:44:14 -0500276blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev)
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500277{
278 blkid_tag_iterate iter;
279
bigbiff7b4c7a62015-01-01 19:44:14 -0500280 if (!dev) {
281 errno = EINVAL;
282 return NULL;
283 }
284
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500285 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 */
bigbiff7b4c7a62015-01-01 19:44:14 -0500297int blkid_tag_next(blkid_tag_iterate iter,
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500298 const char **type, const char **value)
299{
300 blkid_tag tag;
301
302 if (!type || !value ||
303 !iter || iter->magic != TAG_ITERATE_MAGIC ||
304 iter->p == &iter->dev->bid_tags)
305 return -1;
306
307 *type = 0;
308 *value = 0;
309 tag = list_entry(iter->p, struct blkid_struct_tag, bit_tags);
310 *type = tag->bit_name;
311 *value = tag->bit_val;
312 iter->p = iter->p->next;
313 return 0;
314}
315
bigbiff7b4c7a62015-01-01 19:44:14 -0500316void blkid_tag_iterate_end(blkid_tag_iterate iter)
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500317{
318 if (!iter || iter->magic != TAG_ITERATE_MAGIC)
319 return;
320 iter->magic = 0;
321 free(iter);
322}
323
324/*
325 * This function returns a device which matches a particular
326 * type/value pair. If there is more than one device that matches the
327 * search specification, it returns the one with the highest priority
328 * value. This allows us to give preference to EVMS or LVM devices.
329 */
bigbiff7b4c7a62015-01-01 19:44:14 -0500330blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500331 const char *type,
332 const char *value)
333{
334 blkid_tag head;
335 blkid_dev dev;
336 int pri;
337 struct list_head *p;
338 int probe_new = 0;
339
340 if (!cache || !type || !value)
341 return NULL;
342
343 blkid_read_cache(cache);
344
bigbiff7b4c7a62015-01-01 19:44:14 -0500345 DBG(TAG, ul_debug("looking for %s=%s in cache", type, value));
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500346
347try_again:
348 pri = -1;
349 dev = 0;
350 head = blkid_find_head_cache(cache, type);
351
352 if (head) {
353 list_for_each(p, &head->bit_names) {
354 blkid_tag tmp = list_entry(p, struct blkid_struct_tag,
355 bit_names);
356
357 if (!strcmp(tmp->bit_val, value) &&
358 (tmp->bit_dev->bid_pri > pri) &&
359 !access(tmp->bit_dev->bid_name, F_OK)) {
360 dev = tmp->bit_dev;
361 pri = dev->bid_pri;
362 }
363 }
364 }
365 if (dev && !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) {
366 dev = blkid_verify(cache, dev);
367 if (!dev || (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED)))
368 goto try_again;
369 }
370
371 if (!dev && !probe_new) {
372 if (blkid_probe_all_new(cache) < 0)
373 return NULL;
374 probe_new++;
375 goto try_again;
376 }
377
378 if (!dev && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) {
379 if (blkid_probe_all(cache) < 0)
380 return NULL;
381 goto try_again;
382 }
383 return dev;
384}
385
386#ifdef TEST_PROGRAM
387#ifdef HAVE_GETOPT_H
388#include <getopt.h>
389#else
390extern char *optarg;
391extern int optind;
392#endif
393
394void __attribute__((__noreturn__)) usage(char *prog)
395{
396 fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask] device "
397 "[type value]\n",
398 prog);
399 fprintf(stderr, "\tList all tags for a device and exit\n");
400 exit(1);
401}
402
403int main(int argc, char **argv)
404{
405 blkid_tag_iterate iter;
406 blkid_cache cache = NULL;
407 blkid_dev dev;
408 int c, ret, found;
409 int flags = BLKID_DEV_FIND;
410 char *tmp;
411 char *file = NULL;
412 char *devname = NULL;
413 char *search_type = NULL;
414 char *search_value = NULL;
415 const char *type, *value;
416
417 while ((c = getopt (argc, argv, "m:f:")) != EOF)
418 switch (c) {
419 case 'f':
420 file = optarg;
421 break;
422 case 'm':
423 {
424 int mask = strtoul (optarg, &tmp, 0);
425 if (*tmp) {
426 fprintf(stderr, "Invalid debug mask: %s\n",
427 optarg);
428 exit(1);
429 }
430 blkid_init_debug(mask);
431 break;
432 }
433 case '?':
434 usage(argv[0]);
435 }
436 if (argc > optind)
437 devname = argv[optind++];
438 if (argc > optind)
439 search_type = argv[optind++];
440 if (argc > optind)
441 search_value = argv[optind++];
442 if (!devname || (argc != optind))
443 usage(argv[0]);
444
445 if ((ret = blkid_get_cache(&cache, file)) != 0) {
446 fprintf(stderr, "%s: error creating cache (%d)\n",
447 argv[0], ret);
448 exit(1);
449 }
450
451 dev = blkid_get_dev(cache, devname, flags);
452 if (!dev) {
453 fprintf(stderr, "%s: Can not find device in blkid cache\n",
454 devname);
455 exit(1);
456 }
457 if (search_type) {
458 found = blkid_dev_has_tag(dev, search_type, search_value);
459 printf("Device %s: (%s, %s) %s\n", blkid_dev_devname(dev),
460 search_type, search_value ? search_value : "NULL",
461 found ? "FOUND" : "NOT FOUND");
462 return(!found);
463 }
464 printf("Device %s...\n", blkid_dev_devname(dev));
465
466 iter = blkid_tag_iterate_begin(dev);
467 while (blkid_tag_next(iter, &type, &value) == 0) {
468 printf("\tTag %s has value %s\n", type, value);
469 }
470 blkid_tag_iterate_end(iter);
471
472 blkid_put_cache(cache);
473 return (0);
474}
475#endif