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