blob: 9dbacef04dbd2f12e182b62cb9975a623a3a06ee [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
33#ifdef CONFIG_BLKID_DEBUG
34void 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
45void 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 */
67blkid_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
84extern int blkid_dev_has_tag(blkid_dev dev, const char *type,
85 const char *value)
86{
87 blkid_tag tag;
88
89 tag = blkid_find_tag_dev(dev, type);
90 if (!value)
91 return (tag != NULL);
92 if (!tag || strcmp(tag->bit_val, value))
93 return 0;
94 return 1;
95}
96
97/*
98 * Find the desired tag type in the cache.
99 * We return the head tag for this tag type.
100 */
101static blkid_tag blkid_find_head_cache(blkid_cache cache, const char *type)
102{
103 blkid_tag head = NULL, tmp;
104 struct list_head *p;
105
106 if (!cache || !type)
107 return NULL;
108
109 list_for_each(p, &cache->bic_tags) {
110 tmp = list_entry(p, struct blkid_struct_tag, bit_tags);
111 if (!strcmp(tmp->bit_name, type)) {
112 DBG(DEBUG_TAG,
113 printf(" found cache tag head %s\n", type));
114 head = tmp;
115 break;
116 }
117 }
118 return head;
119}
120
121/*
122 * Set a tag on an existing device.
123 *
124 * If value is NULL, then delete the tagsfrom the device.
125 */
126int blkid_set_tag(blkid_dev dev, const char *name,
127 const char *value, const int vlength)
128{
129 blkid_tag t = 0, head = 0;
130 char *val = 0;
131 char **dev_var = 0;
132
133 if (!dev || !name)
134 return -BLKID_ERR_PARAM;
135
136 if (value && !(val = strndup(value, vlength)))
137 return -BLKID_ERR_MEM;
138
139 /*
140 * Certain common tags are linked directly to the device struct
141 * We need to know what they are before we do anything else because
142 * the function name parameter might get freed later on.
143 */
144 if (!strcmp(name, "TYPE"))
145 dev_var = &dev->bid_type;
146 else if (!strcmp(name, "LABEL"))
147 dev_var = &dev->bid_label;
148 else if (!strcmp(name, "UUID"))
149 dev_var = &dev->bid_uuid;
150
151 t = blkid_find_tag_dev(dev, name);
152 if (!value) {
153 if (t)
154 blkid_free_tag(t);
155 } else if (t) {
156 if (!strcmp(t->bit_val, val)) {
157 /* Same thing, exit */
158 free(val);
159 return 0;
160 }
161 free(t->bit_val);
162 t->bit_val = val;
163 } else {
164 /* Existing tag not present, add to device */
165 if (!(t = blkid_new_tag()))
166 goto errout;
167 t->bit_name = name ? strdup(name) : NULL;
168 t->bit_val = val;
169 t->bit_dev = dev;
170
171 list_add_tail(&t->bit_tags, &dev->bid_tags);
172
173 if (dev->bid_cache) {
174 head = blkid_find_head_cache(dev->bid_cache,
175 t->bit_name);
176 if (!head) {
177 head = blkid_new_tag();
178 if (!head)
179 goto errout;
180
181 DBG(DEBUG_TAG,
182 printf(" creating new cache tag head %s\n", name));
183 head->bit_name = name ? strdup(name) : NULL;
184 if (!head->bit_name)
185 goto errout;
186 list_add_tail(&head->bit_tags,
187 &dev->bid_cache->bic_tags);
188 }
189 list_add_tail(&t->bit_names, &head->bit_names);
190 }
191 }
192
193 /* Link common tags directly to the device struct */
194 if (dev_var)
195 *dev_var = val;
196
197 if (dev->bid_cache)
198 dev->bid_cache->bic_flags |= BLKID_BIC_FL_CHANGED;
199 return 0;
200
201errout:
202 if (t)
203 blkid_free_tag(t);
204 else
205 free(val);
206 if (head)
207 blkid_free_tag(head);
208 return -BLKID_ERR_MEM;
209}
210
211
212/*
213 * Parse a "NAME=value" string. This is slightly different than
214 * parse_token, because that will end an unquoted value at a space, while
215 * this will assume that an unquoted value is the rest of the token (e.g.
216 * if we are passed an already quoted string from the command-line we don't
217 * have to both quote and escape quote so that the quotes make it to
218 * us).
219 *
220 * Returns 0 on success, and -1 on failure.
221 */
222int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val)
223{
224 char *name, *value, *cp;
225
226 DBG(DEBUG_TAG, printf("trying to parse '%s' as a tag\n", token));
227
228 if (!token || !(cp = strchr(token, '=')))
229 return -1;
230
231 name = strdup(token);
232 if (!name)
233 return -1;
234 value = name + (cp - token);
235 *value++ = '\0';
236 if (*value == '"' || *value == '\'') {
237 char c = *value++;
238 if (!(cp = strrchr(value, c)))
239 goto errout; /* missing closing quote */
240 *cp = '\0';
241 }
242 if (value && *value)
243 value = strdup(value);
244 if (!value)
245 goto errout;
246
247 if (ret_type)
248 *ret_type = name;
249 if (ret_val)
250 *ret_val = value;
251
252 return 0;
253
254errout:
255 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
282extern blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev)
283{
284 blkid_tag_iterate iter;
285
286 iter = malloc(sizeof(struct blkid_struct_tag_iterate));
287 if (iter) {
288 iter->magic = TAG_ITERATE_MAGIC;
289 iter->dev = dev;
290 iter->p = dev->bid_tags.next;
291 }
292 return (iter);
293}
294
295/*
296 * Return 0 on success, -1 on error
297 */
298extern int blkid_tag_next(blkid_tag_iterate iter,
299 const char **type, const char **value)
300{
301 blkid_tag tag;
302
303 if (!type || !value ||
304 !iter || iter->magic != TAG_ITERATE_MAGIC ||
305 iter->p == &iter->dev->bid_tags)
306 return -1;
307
308 *type = 0;
309 *value = 0;
310 tag = list_entry(iter->p, struct blkid_struct_tag, bit_tags);
311 *type = tag->bit_name;
312 *value = tag->bit_val;
313 iter->p = iter->p->next;
314 return 0;
315}
316
317extern void blkid_tag_iterate_end(blkid_tag_iterate iter)
318{
319 if (!iter || iter->magic != TAG_ITERATE_MAGIC)
320 return;
321 iter->magic = 0;
322 free(iter);
323}
324
325/*
326 * This function returns a device which matches a particular
327 * type/value pair. If there is more than one device that matches the
328 * search specification, it returns the one with the highest priority
329 * value. This allows us to give preference to EVMS or LVM devices.
330 */
331extern blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
332 const char *type,
333 const char *value)
334{
335 blkid_tag head;
336 blkid_dev dev;
337 int pri;
338 struct list_head *p;
339 int probe_new = 0;
340
341 if (!cache || !type || !value)
342 return NULL;
343
344 blkid_read_cache(cache);
345
346 DBG(DEBUG_TAG, printf("looking for %s=%s in cache\n", type, value));
347
348try_again:
349 pri = -1;
350 dev = 0;
351 head = blkid_find_head_cache(cache, type);
352
353 if (head) {
354 list_for_each(p, &head->bit_names) {
355 blkid_tag tmp = list_entry(p, struct blkid_struct_tag,
356 bit_names);
357
358 if (!strcmp(tmp->bit_val, value) &&
359 (tmp->bit_dev->bid_pri > pri) &&
360 !access(tmp->bit_dev->bid_name, F_OK)) {
361 dev = tmp->bit_dev;
362 pri = dev->bid_pri;
363 }
364 }
365 }
366 if (dev && !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) {
367 dev = blkid_verify(cache, dev);
368 if (!dev || (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED)))
369 goto try_again;
370 }
371
372 if (!dev && !probe_new) {
373 if (blkid_probe_all_new(cache) < 0)
374 return NULL;
375 probe_new++;
376 goto try_again;
377 }
378
379 if (!dev && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) {
380 if (blkid_probe_all(cache) < 0)
381 return NULL;
382 goto try_again;
383 }
384 return dev;
385}
386
387#ifdef TEST_PROGRAM
388#ifdef HAVE_GETOPT_H
389#include <getopt.h>
390#else
391extern char *optarg;
392extern int optind;
393#endif
394
395void __attribute__((__noreturn__)) usage(char *prog)
396{
397 fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask] device "
398 "[type value]\n",
399 prog);
400 fprintf(stderr, "\tList all tags for a device and exit\n");
401 exit(1);
402}
403
404int main(int argc, char **argv)
405{
406 blkid_tag_iterate iter;
407 blkid_cache cache = NULL;
408 blkid_dev dev;
409 int c, ret, found;
410 int flags = BLKID_DEV_FIND;
411 char *tmp;
412 char *file = NULL;
413 char *devname = NULL;
414 char *search_type = NULL;
415 char *search_value = NULL;
416 const char *type, *value;
417
418 while ((c = getopt (argc, argv, "m:f:")) != EOF)
419 switch (c) {
420 case 'f':
421 file = optarg;
422 break;
423 case 'm':
424 {
425 int mask = strtoul (optarg, &tmp, 0);
426 if (*tmp) {
427 fprintf(stderr, "Invalid debug mask: %s\n",
428 optarg);
429 exit(1);
430 }
431 blkid_init_debug(mask);
432 break;
433 }
434 case '?':
435 usage(argv[0]);
436 }
437 if (argc > optind)
438 devname = argv[optind++];
439 if (argc > optind)
440 search_type = argv[optind++];
441 if (argc > optind)
442 search_value = argv[optind++];
443 if (!devname || (argc != optind))
444 usage(argv[0]);
445
446 if ((ret = blkid_get_cache(&cache, file)) != 0) {
447 fprintf(stderr, "%s: error creating cache (%d)\n",
448 argv[0], ret);
449 exit(1);
450 }
451
452 dev = blkid_get_dev(cache, devname, flags);
453 if (!dev) {
454 fprintf(stderr, "%s: Can not find device in blkid cache\n",
455 devname);
456 exit(1);
457 }
458 if (search_type) {
459 found = blkid_dev_has_tag(dev, search_type, search_value);
460 printf("Device %s: (%s, %s) %s\n", blkid_dev_devname(dev),
461 search_type, search_value ? search_value : "NULL",
462 found ? "FOUND" : "NOT FOUND");
463 return(!found);
464 }
465 printf("Device %s...\n", blkid_dev_devname(dev));
466
467 iter = blkid_tag_iterate_begin(dev);
468 while (blkid_tag_next(iter, &type, &value) == 0) {
469 printf("\tTag %s has value %s\n", type, value);
470 }
471 blkid_tag_iterate_end(iter);
472
473 blkid_put_cache(cache);
474 return (0);
475}
476#endif