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