]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libblkid/src/tag.c
Merge branch 'spelling' of https://github.com/jwilk-forks/util-linux
[thirdparty/util-linux.git] / libblkid / src / tag.c
CommitLineData
a0948ffe
KZ
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
20static blkid_tag blkid_new_tag(void)
21{
22 blkid_tag tag;
23
fea1cbf7 24 if (!(tag = calloc(1, sizeof(struct blkid_struct_tag))))
a0948ffe
KZ
25 return NULL;
26
14308bc3 27 DBG(TAG, ul_debugobj(tag, "alloc"));
a0948ffe
KZ
28 INIT_LIST_HEAD(&tag->bit_tags);
29 INIT_LIST_HEAD(&tag->bit_names);
30
31 return tag;
32}
33
a0948ffe
KZ
34void blkid_free_tag(blkid_tag tag)
35{
36 if (!tag)
37 return;
38
14308bc3 39 DBG(TAG, ul_debugobj(tag, "freeing tag %s (%s)", tag->bit_name, tag->bit_val));
a0948ffe
KZ
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
0e4ed1aa
JM
44 free(tag->bit_name);
45 free(tag->bit_val);
a0948ffe
KZ
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 */
54blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type)
55{
56 struct list_head *p;
57
a0948ffe
KZ
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
604ba973 68int blkid_dev_has_tag(blkid_dev dev, const char *type,
a0948ffe
KZ
69 const char *value)
70{
71 blkid_tag tag;
72
a0948ffe
KZ
73 tag = blkid_find_tag_dev(dev, type);
74 if (!value)
75 return (tag != NULL);
ad296391 76 if (!tag || strcmp(tag->bit_val, value) != 0)
a0948ffe
KZ
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 */
85static 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)) {
14308bc3 96 DBG(TAG, ul_debug("found cache tag head %s", type));
a0948ffe
KZ
97 head = tmp;
98 break;
99 }
100 }
101 return head;
102}
103
104/*
105 * Set a tag on an existing device.
106 *
9e930041 107 * If value is NULL, then delete the tags from the device.
a0948ffe
KZ
108 */
109int blkid_set_tag(blkid_dev dev, const char *name,
110 const char *value, const int vlength)
111{
87918040
SK
112 blkid_tag t = NULL, head = NULL;
113 char *val = NULL;
114 char **dev_var = NULL;
a0948ffe 115
e0a9b8cf 116 if (value && !(val = strndup(value, vlength)))
a0948ffe
KZ
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 }
14308bc3 141 DBG(TAG, ul_debugobj(t, "update (%s) '%s' -> '%s'", t->bit_name, t->bit_val, val));
a0948ffe
KZ
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;
e97c0214 148 t->bit_name = strdup(name);
a0948ffe
KZ
149 t->bit_val = val;
150 t->bit_dev = dev;
151
14308bc3 152 DBG(TAG, ul_debugobj(t, "setting (%s) '%s'", t->bit_name, t->bit_val));
a0948ffe
KZ
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
14308bc3 163 DBG(TAG, ul_debugobj(head, "creating new cache tag head %s", name));
e97c0214 164 head->bit_name = strdup(name);
a0948ffe
KZ
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
182errout:
183 if (t)
184 blkid_free_tag(t);
c8f1e920
KZ
185 else
186 free(val);
a0948ffe
KZ
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 */
203int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val)
204{
205 char *name, *value, *cp;
206
c62a6311 207 DBG(TAG, ul_debug("trying to parse '%s' as a tag", token));
a0948ffe
KZ
208
209 if (!token || !(cp = strchr(token, '=')))
210 return -1;
211
e0a9b8cf 212 name = strdup(token);
a0948ffe
KZ
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 }
c1178175
KZ
223
224 if (ret_val) {
e97c0214 225 value = *value ? strdup(value) : NULL;
c1178175
KZ
226 if (!value)
227 goto errout;
228 *ret_val = value;
229 }
a0948ffe 230
e3436956
KZ
231 if (ret_type)
232 *ret_type = name;
c1178175
KZ
233 else
234 free(name);
a0948ffe
KZ
235
236 return 0;
237
238errout:
c62a6311 239 DBG(TAG, ul_debug("parse error: '%s'", token));
a0948ffe
KZ
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
9e930041 249 * too much of our internal implementation. I'm not convinced I want
a0948ffe
KZ
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
9e930041 252 * library, and I really don't like the trade-off of type-safety for
a0948ffe
KZ
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
261struct blkid_struct_tag_iterate {
262 int magic;
263 blkid_dev dev;
264 struct list_head *p;
265};
266
604ba973 267blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev)
a0948ffe
KZ
268{
269 blkid_tag_iterate iter;
270
2bb7a706
KZ
271 if (!dev) {
272 errno = EINVAL;
273 return NULL;
274 }
275
a0948ffe
KZ
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 */
604ba973 288int blkid_tag_next(blkid_tag_iterate iter,
a0948ffe
KZ
289 const char **type, const char **value)
290{
291 blkid_tag tag;
292
e3436956
KZ
293 if (!type || !value ||
294 !iter || iter->magic != TAG_ITERATE_MAGIC ||
a0948ffe
KZ
295 iter->p == &iter->dev->bid_tags)
296 return -1;
e3436956 297
87918040
SK
298 *type = NULL;
299 *value = NULL;
a0948ffe
KZ
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
604ba973 307void blkid_tag_iterate_end(blkid_tag_iterate iter)
a0948ffe
KZ
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 */
604ba973 321blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
a0948ffe
KZ
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;
84d38ae3 329 int probe_new = 0, probe_all = 0;
a0948ffe
KZ
330
331 if (!cache || !type || !value)
332 return NULL;
333
334 blkid_read_cache(cache);
335
84d38ae3 336 DBG(TAG, ul_debug("looking for tag %s=%s in cache", type, value));
a0948ffe
KZ
337
338try_again:
339 pri = -1;
87918040 340 dev = NULL;
a0948ffe
KZ
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);
7508d991 358 if (!dev || dev->bid_flags & BLKID_BID_FL_VERIFIED)
a0948ffe
KZ
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
84d38ae3
KZ
369 if (!dev && !probe_all
370 && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) {
a0948ffe
KZ
371 if (blkid_probe_all(cache) < 0)
372 return NULL;
84d38ae3 373 probe_all++;
a0948ffe
KZ
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
383extern char *optarg;
384extern int optind;
385#endif
386
5fde1d9f 387static void __attribute__((__noreturn__)) usage(char *prog)
a0948ffe
KZ
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
396int 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':
6644688a
KZ
416 {
417 int mask = strtoul (optarg, &tmp, 0);
a0948ffe
KZ
418 if (*tmp) {
419 fprintf(stderr, "Invalid debug mask: %s\n",
420 optarg);
421 exit(1);
422 }
7a458332 423 blkid_init_debug(mask);
a0948ffe 424 break;
6644688a 425 }
a0948ffe
KZ
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) {
223939d9 446 fprintf(stderr, "%s: cannot find device in blkid cache\n",
a0948ffe
KZ
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