blob: 6af806251008cc47b36cdb36b3424a1e7a89e005 [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
69 if (!dev || !type)
70 return NULL;
71
72 list_for_each(p, &dev->bid_tags) {
73 blkid_tag tmp = list_entry(p, struct blkid_struct_tag,
74 bit_tags);
75
76 if (!strcmp(tmp->bit_name, type))
77 return tmp;
78 }
79 return NULL;
80}
81
bigbiff7b4c7a62015-01-01 19:44:14 -050082int blkid_dev_has_tag(blkid_dev dev, const char *type,
bigbiff bigbiffe60683a2013-02-22 20:55:50 -050083 const char *value)
84{
85 blkid_tag tag;
86
87 tag = blkid_find_tag_dev(dev, type);
88 if (!value)
89 return (tag != NULL);
90 if (!tag || strcmp(tag->bit_val, value))
91 return 0;
92 return 1;
93}
94
95/*
96 * Find the desired tag type in the cache.
97 * We return the head tag for this tag type.
98 */
99static blkid_tag blkid_find_head_cache(blkid_cache cache, const char *type)
100{
101 blkid_tag head = NULL, tmp;
102 struct list_head *p;
103
104 if (!cache || !type)
105 return NULL;
106
107 list_for_each(p, &cache->bic_tags) {
108 tmp = list_entry(p, struct blkid_struct_tag, bit_tags);
109 if (!strcmp(tmp->bit_name, type)) {
bigbiff7b4c7a62015-01-01 19:44:14 -0500110 DBG(TAG, ul_debug(" found cache tag head %s", type));
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500111 head = tmp;
112 break;
113 }
114 }
115 return head;
116}
117
118/*
119 * Set a tag on an existing device.
120 *
121 * If value is NULL, then delete the tagsfrom the device.
122 */
123int blkid_set_tag(blkid_dev dev, const char *name,
124 const char *value, const int vlength)
125{
126 blkid_tag t = 0, head = 0;
127 char *val = 0;
128 char **dev_var = 0;
129
130 if (!dev || !name)
131 return -BLKID_ERR_PARAM;
132
133 if (value && !(val = strndup(value, vlength)))
134 return -BLKID_ERR_MEM;
135
136 /*
137 * Certain common tags are linked directly to the device struct
138 * We need to know what they are before we do anything else because
139 * the function name parameter might get freed later on.
140 */
141 if (!strcmp(name, "TYPE"))
142 dev_var = &dev->bid_type;
143 else if (!strcmp(name, "LABEL"))
144 dev_var = &dev->bid_label;
145 else if (!strcmp(name, "UUID"))
146 dev_var = &dev->bid_uuid;
147
148 t = blkid_find_tag_dev(dev, name);
149 if (!value) {
150 if (t)
151 blkid_free_tag(t);
152 } else if (t) {
153 if (!strcmp(t->bit_val, val)) {
154 /* Same thing, exit */
155 free(val);
156 return 0;
157 }
158 free(t->bit_val);
159 t->bit_val = val;
160 } else {
161 /* Existing tag not present, add to device */
162 if (!(t = blkid_new_tag()))
163 goto errout;
164 t->bit_name = name ? strdup(name) : NULL;
165 t->bit_val = val;
166 t->bit_dev = dev;
167
168 list_add_tail(&t->bit_tags, &dev->bid_tags);
169
170 if (dev->bid_cache) {
171 head = blkid_find_head_cache(dev->bid_cache,
172 t->bit_name);
173 if (!head) {
174 head = blkid_new_tag();
175 if (!head)
176 goto errout;
177
bigbiff7b4c7a62015-01-01 19:44:14 -0500178 DBG(TAG, ul_debug(" creating new cache tag head %s", name));
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500179 head->bit_name = name ? strdup(name) : NULL;
180 if (!head->bit_name)
181 goto errout;
182 list_add_tail(&head->bit_tags,
183 &dev->bid_cache->bic_tags);
184 }
185 list_add_tail(&t->bit_names, &head->bit_names);
186 }
187 }
188
189 /* Link common tags directly to the device struct */
190 if (dev_var)
191 *dev_var = val;
192
193 if (dev->bid_cache)
194 dev->bid_cache->bic_flags |= BLKID_BIC_FL_CHANGED;
195 return 0;
196
197errout:
198 if (t)
199 blkid_free_tag(t);
200 else
201 free(val);
202 if (head)
203 blkid_free_tag(head);
204 return -BLKID_ERR_MEM;
205}
206
207
208/*
209 * Parse a "NAME=value" string. This is slightly different than
210 * parse_token, because that will end an unquoted value at a space, while
211 * this will assume that an unquoted value is the rest of the token (e.g.
212 * if we are passed an already quoted string from the command-line we don't
213 * have to both quote and escape quote so that the quotes make it to
214 * us).
215 *
216 * Returns 0 on success, and -1 on failure.
217 */
218int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val)
219{
220 char *name, *value, *cp;
221
bigbiff7b4c7a62015-01-01 19:44:14 -0500222 DBG(TAG, ul_debug("trying to parse '%s' as a tag", token));
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500223
224 if (!token || !(cp = strchr(token, '=')))
225 return -1;
226
227 name = strdup(token);
228 if (!name)
229 return -1;
230 value = name + (cp - token);
231 *value++ = '\0';
232 if (*value == '"' || *value == '\'') {
233 char c = *value++;
234 if (!(cp = strrchr(value, c)))
235 goto errout; /* missing closing quote */
236 *cp = '\0';
237 }
bigbiff7b4c7a62015-01-01 19:44:14 -0500238
239 if (ret_val) {
240 value = value && *value ? strdup(value) : NULL;
241 if (!value)
242 goto errout;
243 *ret_val = value;
244 }
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500245
246 if (ret_type)
247 *ret_type = name;
bigbiff7b4c7a62015-01-01 19:44:14 -0500248 else
249 free(name);
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500250
251 return 0;
252
253errout:
bigbiff7b4c7a62015-01-01 19:44:14 -0500254 DBG(TAG, ul_debug("parse error: '%s'", token));
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500255 free(name);
256 return -1;
257}
258
259/*
260 * Tag iteration routines for the public libblkid interface.
261 *
262 * These routines do not expose the list.h implementation, which are a
263 * contamination of the namespace, and which force us to reveal far, far
264 * too much of our internal implemenation. I'm not convinced I want
265 * to keep list.h in the long term, anyway. It's fine for kernel
266 * programming, but performance is not the #1 priority for this
267 * library, and I really don't like the tradeoff of type-safety for
268 * performance for this application. [tytso:20030125.2007EST]
269 */
270
271/*
272 * This series of functions iterate over all tags in a device
273 */
274#define TAG_ITERATE_MAGIC 0x01a5284c
275
276struct blkid_struct_tag_iterate {
277 int magic;
278 blkid_dev dev;
279 struct list_head *p;
280};
281
bigbiff7b4c7a62015-01-01 19:44:14 -0500282blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev)
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500283{
284 blkid_tag_iterate iter;
285
bigbiff7b4c7a62015-01-01 19:44:14 -0500286 if (!dev) {
287 errno = EINVAL;
288 return NULL;
289 }
290
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500291 iter = malloc(sizeof(struct blkid_struct_tag_iterate));
292 if (iter) {
293 iter->magic = TAG_ITERATE_MAGIC;
294 iter->dev = dev;
295 iter->p = dev->bid_tags.next;
296 }
297 return (iter);
298}
299
300/*
301 * Return 0 on success, -1 on error
302 */
bigbiff7b4c7a62015-01-01 19:44:14 -0500303int blkid_tag_next(blkid_tag_iterate iter,
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500304 const char **type, const char **value)
305{
306 blkid_tag tag;
307
308 if (!type || !value ||
309 !iter || iter->magic != TAG_ITERATE_MAGIC ||
310 iter->p == &iter->dev->bid_tags)
311 return -1;
312
313 *type = 0;
314 *value = 0;
315 tag = list_entry(iter->p, struct blkid_struct_tag, bit_tags);
316 *type = tag->bit_name;
317 *value = tag->bit_val;
318 iter->p = iter->p->next;
319 return 0;
320}
321
bigbiff7b4c7a62015-01-01 19:44:14 -0500322void blkid_tag_iterate_end(blkid_tag_iterate iter)
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500323{
324 if (!iter || iter->magic != TAG_ITERATE_MAGIC)
325 return;
326 iter->magic = 0;
327 free(iter);
328}
329
330/*
331 * This function returns a device which matches a particular
332 * type/value pair. If there is more than one device that matches the
333 * search specification, it returns the one with the highest priority
334 * value. This allows us to give preference to EVMS or LVM devices.
335 */
bigbiff7b4c7a62015-01-01 19:44:14 -0500336blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500337 const char *type,
338 const char *value)
339{
340 blkid_tag head;
341 blkid_dev dev;
342 int pri;
343 struct list_head *p;
344 int probe_new = 0;
345
346 if (!cache || !type || !value)
347 return NULL;
348
349 blkid_read_cache(cache);
350
bigbiff7b4c7a62015-01-01 19:44:14 -0500351 DBG(TAG, ul_debug("looking for %s=%s in cache", type, value));
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500352
353try_again:
354 pri = -1;
355 dev = 0;
356 head = blkid_find_head_cache(cache, type);
357
358 if (head) {
359 list_for_each(p, &head->bit_names) {
360 blkid_tag tmp = list_entry(p, struct blkid_struct_tag,
361 bit_names);
362
363 if (!strcmp(tmp->bit_val, value) &&
364 (tmp->bit_dev->bid_pri > pri) &&
365 !access(tmp->bit_dev->bid_name, F_OK)) {
366 dev = tmp->bit_dev;
367 pri = dev->bid_pri;
368 }
369 }
370 }
371 if (dev && !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) {
372 dev = blkid_verify(cache, dev);
373 if (!dev || (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED)))
374 goto try_again;
375 }
376
377 if (!dev && !probe_new) {
378 if (blkid_probe_all_new(cache) < 0)
379 return NULL;
380 probe_new++;
381 goto try_again;
382 }
383
384 if (!dev && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) {
385 if (blkid_probe_all(cache) < 0)
386 return NULL;
387 goto try_again;
388 }
389 return dev;
390}
391
392#ifdef TEST_PROGRAM
393#ifdef HAVE_GETOPT_H
394#include <getopt.h>
395#else
396extern char *optarg;
397extern int optind;
398#endif
399
400void __attribute__((__noreturn__)) usage(char *prog)
401{
402 fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask] device "
403 "[type value]\n",
404 prog);
405 fprintf(stderr, "\tList all tags for a device and exit\n");
406 exit(1);
407}
408
409int main(int argc, char **argv)
410{
411 blkid_tag_iterate iter;
412 blkid_cache cache = NULL;
413 blkid_dev dev;
414 int c, ret, found;
415 int flags = BLKID_DEV_FIND;
416 char *tmp;
417 char *file = NULL;
418 char *devname = NULL;
419 char *search_type = NULL;
420 char *search_value = NULL;
421 const char *type, *value;
422
423 while ((c = getopt (argc, argv, "m:f:")) != EOF)
424 switch (c) {
425 case 'f':
426 file = optarg;
427 break;
428 case 'm':
429 {
430 int mask = strtoul (optarg, &tmp, 0);
431 if (*tmp) {
432 fprintf(stderr, "Invalid debug mask: %s\n",
433 optarg);
434 exit(1);
435 }
436 blkid_init_debug(mask);
437 break;
438 }
439 case '?':
440 usage(argv[0]);
441 }
442 if (argc > optind)
443 devname = argv[optind++];
444 if (argc > optind)
445 search_type = argv[optind++];
446 if (argc > optind)
447 search_value = argv[optind++];
448 if (!devname || (argc != optind))
449 usage(argv[0]);
450
451 if ((ret = blkid_get_cache(&cache, file)) != 0) {
452 fprintf(stderr, "%s: error creating cache (%d)\n",
453 argv[0], ret);
454 exit(1);
455 }
456
457 dev = blkid_get_dev(cache, devname, flags);
458 if (!dev) {
459 fprintf(stderr, "%s: Can not find device in blkid cache\n",
460 devname);
461 exit(1);
462 }
463 if (search_type) {
464 found = blkid_dev_has_tag(dev, search_type, search_value);
465 printf("Device %s: (%s, %s) %s\n", blkid_dev_devname(dev),
466 search_type, search_value ? search_value : "NULL",
467 found ? "FOUND" : "NOT FOUND");
468 return(!found);
469 }
470 printf("Device %s...\n", blkid_dev_devname(dev));
471
472 iter = blkid_tag_iterate_begin(dev);
473 while (blkid_tag_next(iter, &type, &value) == 0) {
474 printf("\tTag %s has value %s\n", type, value);
475 }
476 blkid_tag_iterate_end(iter);
477
478 blkid_put_cache(cache);
479 return (0);
480}
481#endif