]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libmount/src/cache.c
misc: fix reassigned values before old ones has been used [cppcheck]
[thirdparty/util-linux.git] / libmount / src / cache.c
CommitLineData
7755ca95 1/*
63de90d4 2 * Copyright (C) 2009-2011 Karel Zak <kzak@redhat.com>
7755ca95
KZ
3 *
4 * This file may be redistributed under the terms of the
5 * GNU Lesser General Public License.
6 */
7
192c6aad
KZ
8/**
9 * SECTION: cache
10 * @title: Cache
11 * @short_description: paths and tags (UUID/LABEL) caching
12 *
d58b3157 13 * The cache is a very simple API for working with tags (LABEL, UUID, ...) and
63de90d4 14 * paths. The cache uses libblkid as a backend for TAGs resolution.
192c6aad
KZ
15 *
16 * All returned paths are always canonicalized.
17 */
7755ca95
KZ
18#include <string.h>
19#include <stdlib.h>
20#include <ctype.h>
21#include <limits.h>
7755ca95
KZ
22#include <sys/stat.h>
23#include <unistd.h>
24#include <fcntl.h>
25#include <blkid.h>
26
27#include "canonicalize.h"
28#include "mountP.h"
2576b4e7 29#include "loopdev.h"
0382ba32 30#include "strutils.h"
7755ca95
KZ
31
32/*
192c6aad 33 * Canonicalized (resolved) paths & tags cache
7755ca95
KZ
34 */
35#define MNT_CACHE_CHUNKSZ 128
36
2e67aee9 37#define MNT_CACHE_ISTAG (1 << 1) /* entry is TAG */
7755ca95
KZ
38#define MNT_CACHE_ISPATH (1 << 2) /* entry is path */
39#define MNT_CACHE_TAGREAD (1 << 3) /* tag read by mnt_cache_read_tags() */
40
41/* path cache entry */
42struct mnt_cache_entry {
8eef6df7
KZ
43 char *key; /* search key (e.g. uncanonicalized path) */
44 char *value; /* value (e.g. canonicalized path) */
7755ca95
KZ
45 int flag;
46};
47
68164f6c 48struct libmnt_cache {
7755ca95
KZ
49 struct mnt_cache_entry *ents;
50 size_t nents;
51 size_t nallocs;
0105691d 52 int refcount;
7755ca95
KZ
53
54 /* blkid_evaluate_tag() works in two ways:
55 *
56 * 1/ all tags are evaluated by udev /dev/disk/by-* symlinks,
57 * then the blkid_cache is NULL.
58 *
b82590ad 59 * 2/ all tags are read from blkid.tab and verified by /dev
7755ca95
KZ
60 * scanning, then the blkid_cache is not NULL and then it's
61 * better to reuse the blkid_cache.
62 */
63 blkid_cache bc;
0382ba32
ER
64
65 struct libmnt_table *mtab;
7755ca95
KZ
66};
67
68/**
69 * mnt_new_cache:
70 *
68164f6c 71 * Returns: new struct libmnt_cache instance or NULL in case of ENOMEM error.
7755ca95 72 */
68164f6c 73struct libmnt_cache *mnt_new_cache(void)
7755ca95 74{
68164f6c 75 struct libmnt_cache *cache = calloc(1, sizeof(*cache));
3f31a959
KZ
76 if (!cache)
77 return NULL;
83a78332 78 DBG(CACHE, ul_debugobj(cache, "alloc"));
0105691d 79 cache->refcount = 1;
3f31a959 80 return cache;
7755ca95
KZ
81}
82
83/**
84 * mnt_free_cache:
68164f6c 85 * @cache: pointer to struct libmnt_cache instance
7755ca95 86 *
c9f1585e 87 * Deallocates the cache. This function does not care about reference count. Don't
a7349ee3 88 * use this function directly -- it's better to use mnt_unref_cache().
7755ca95 89 */
68164f6c 90void mnt_free_cache(struct libmnt_cache *cache)
7755ca95 91{
7fc6d2b8 92 size_t i;
7755ca95
KZ
93
94 if (!cache)
95 return;
3f31a959 96
83a78332 97 DBG(CACHE, ul_debugobj(cache, "free [refcount=%d]", cache->refcount));
3f31a959 98
7755ca95
KZ
99 for (i = 0; i < cache->nents; i++) {
100 struct mnt_cache_entry *e = &cache->ents[i];
8eef6df7
KZ
101 if (e->value != e->key)
102 free(e->value);
103 free(e->key);
7755ca95
KZ
104 }
105 free(cache->ents);
106 if (cache->bc)
107 blkid_put_cache(cache->bc);
108 free(cache);
109}
110
0105691d
KZ
111/**
112 * mnt_ref_cache:
113 * @cache: cache pointer
114 *
115 * Increments reference counter.
116 */
117void mnt_ref_cache(struct libmnt_cache *cache)
118{
119 if (cache) {
120 cache->refcount++;
83a78332 121 /*DBG(CACHE, ul_debugobj(cache, "ref=%d", cache->refcount));*/
0105691d
KZ
122 }
123}
124
125/**
126 * mnt_unref_cache:
127 * @cache: cache pointer
128 *
129 * De-increments reference counter, on zero the cache is automatically
130 * deallocated by mnt_free_cache().
131 */
132void mnt_unref_cache(struct libmnt_cache *cache)
133{
134 if (cache) {
135 cache->refcount--;
83a78332 136 /*DBG(CACHE, ul_debugobj(cache, "unref=%d", cache->refcount));*/
0382ba32
ER
137 if (cache->refcount <= 0) {
138 mnt_unref_table(cache->mtab);
139
0105691d 140 mnt_free_cache(cache);
0382ba32 141 }
0105691d
KZ
142 }
143}
144
0382ba32
ER
145/**
146 * mnt_cache_set_targets:
147 * @cache: cache pointer
148 * @mtab: table with already canonicalized mountpoints
149 *
150 * Add to @cache reference to @mtab. This allows to avoid unnecessary paths
151 * canonicalization in mnt_resolve_target().
152 *
153 * Returns: negative number in case of error, or 0 o success.
154 */
155int mnt_cache_set_targets(struct libmnt_cache *cache,
156 struct libmnt_table *mtab)
157{
0382ba32
ER
158 if (!cache)
159 return -EINVAL;
160
161 mnt_ref_table(mtab);
162 mnt_unref_table(cache->mtab);
163 cache->mtab = mtab;
164 return 0;
165}
166
0105691d 167
d58b3157 168/* note that the @key could be the same pointer as @value */
171b0fb4 169static int cache_add_entry(struct libmnt_cache *cache, char *key,
8eef6df7 170 char *value, int flag)
7755ca95
KZ
171{
172 struct mnt_cache_entry *e;
173
174 assert(cache);
8eef6df7
KZ
175 assert(value);
176 assert(key);
7755ca95
KZ
177
178 if (cache->nents == cache->nallocs) {
179 size_t sz = cache->nallocs + MNT_CACHE_CHUNKSZ;
180
181 e = realloc(cache->ents, sz * sizeof(struct mnt_cache_entry));
182 if (!e)
abc3d154 183 return -ENOMEM;
7755ca95
KZ
184 cache->ents = e;
185 cache->nallocs = sz;
186 }
187
188 e = &cache->ents[cache->nents];
8eef6df7
KZ
189 e->key = key;
190 e->value = value;
7755ca95
KZ
191 e->flag = flag;
192 cache->nents++;
193
83a78332 194 DBG(CACHE, ul_debugobj(cache, "add entry [%2zd] (%s): %s: %s",
2e67aee9
KZ
195 cache->nents,
196 (flag & MNT_CACHE_ISPATH) ? "path" : "tag",
8eef6df7 197 value, key));
7755ca95
KZ
198 return 0;
199}
200
d58b3157 201/* add tag to the cache, @devname has to be an allocated string */
171b0fb4 202static int cache_add_tag(struct libmnt_cache *cache, const char *tagname,
8eef6df7 203 const char *tagval, char *devname, int flag)
7755ca95
KZ
204{
205 size_t tksz, vlsz;
8eef6df7 206 char *key;
abc3d154 207 int rc;
7755ca95
KZ
208
209 assert(cache);
8eef6df7
KZ
210 assert(devname);
211 assert(tagname);
212 assert(tagval);
7755ca95
KZ
213
214 /* add into cache -- cache format for TAGs is
8eef6df7
KZ
215 * key = "TAG_NAME\0TAG_VALUE\0"
216 * value = "/dev/foo"
7755ca95 217 */
8eef6df7
KZ
218 tksz = strlen(tagname);
219 vlsz = strlen(tagval);
7755ca95 220
8eef6df7
KZ
221 key = malloc(tksz + vlsz + 2);
222 if (!key)
abc3d154 223 return -ENOMEM;
7755ca95 224
8eef6df7
KZ
225 memcpy(key, tagname, tksz + 1); /* include '\0' */
226 memcpy(key + tksz + 1, tagval, vlsz + 1);
7755ca95 227
171b0fb4 228 rc = cache_add_entry(cache, key, devname, flag | MNT_CACHE_ISTAG);
abc3d154
KZ
229 if (!rc)
230 return 0;
231
8eef6df7 232 free(key);
abc3d154 233 return rc;
7755ca95
KZ
234}
235
236
d1ce7319
KZ
237/*
238 * Returns cached canonicalized path or NULL.
7755ca95 239 */
171b0fb4 240static const char *cache_find_path(struct libmnt_cache *cache, const char *path)
7755ca95 241{
7fc6d2b8 242 size_t i;
7755ca95 243
7755ca95
KZ
244 if (!cache || !path)
245 return NULL;
246
247 for (i = 0; i < cache->nents; i++) {
248 struct mnt_cache_entry *e = &cache->ents[i];
249 if (!(e->flag & MNT_CACHE_ISPATH))
250 continue;
d4e89dea 251 if (streq_paths(path, e->key))
8eef6df7 252 return e->value;
7755ca95
KZ
253 }
254 return NULL;
255}
256
d1ce7319
KZ
257/*
258 * Returns cached path or NULL.
7755ca95 259 */
171b0fb4 260static const char *cache_find_tag(struct libmnt_cache *cache,
7755ca95
KZ
261 const char *token, const char *value)
262{
7fc6d2b8 263 size_t i;
7755ca95
KZ
264 size_t tksz;
265
7755ca95
KZ
266 if (!cache || !token || !value)
267 return NULL;
268
269 tksz = strlen(token);
270
271 for (i = 0; i < cache->nents; i++) {
272 struct mnt_cache_entry *e = &cache->ents[i];
273 if (!(e->flag & MNT_CACHE_ISTAG))
274 continue;
8eef6df7
KZ
275 if (strcmp(token, e->key) == 0 &&
276 strcmp(value, e->key + tksz + 1) == 0)
277 return e->value;
7755ca95
KZ
278 }
279 return NULL;
280}
281
679f59dd
KZ
282static char *cache_find_tag_value(struct libmnt_cache *cache,
283 const char *devname, const char *token)
284{
7fc6d2b8 285 size_t i;
679f59dd
KZ
286
287 assert(cache);
288 assert(devname);
289 assert(token);
290
291 for (i = 0; i < cache->nents; i++) {
292 struct mnt_cache_entry *e = &cache->ents[i];
293 if (!(e->flag & MNT_CACHE_ISTAG))
294 continue;
295 if (strcmp(e->value, devname) == 0 && /* dev name */
296 strcmp(token, e->key) == 0) /* tag name */
297 return e->key + strlen(token) + 1; /* tag value */
298 }
299
300 return NULL;
301}
302
7755ca95
KZ
303/**
304 * mnt_cache_read_tags
68164f6c 305 * @cache: pointer to struct libmnt_cache instance
7755ca95
KZ
306 * @devname: path device
307 *
308 * Reads @devname LABEL and UUID to the @cache.
309 *
192c6aad 310 * Returns: 0 if at least one tag was added, 1 if no tag was added or
abc3d154 311 * negative number in case of error.
7755ca95 312 */
68164f6c 313int mnt_cache_read_tags(struct libmnt_cache *cache, const char *devname)
7755ca95 314{
6257e445 315 blkid_probe pr;
7fc6d2b8 316 size_t i, ntags = 0;
82a2c160 317 int rc;
cff632af
KZ
318 const char *tags[] = { "LABEL", "UUID", "TYPE", "PARTUUID", "PARTLABEL" };
319 const char *blktags[] = { "LABEL", "UUID", "TYPE", "PART_ENTRY_UUID", "PART_ENTRY_NAME" };
7755ca95 320
7755ca95 321 if (!cache || !devname)
abc3d154 322 return -EINVAL;
7755ca95 323
83a78332 324 DBG(CACHE, ul_debugobj(cache, "tags for %s requested", devname));
6bd8b7a7 325
d58b3157 326 /* check if device is already cached */
7755ca95
KZ
327 for (i = 0; i < cache->nents; i++) {
328 struct mnt_cache_entry *e = &cache->ents[i];
329 if (!(e->flag & MNT_CACHE_TAGREAD))
330 continue;
8eef6df7 331 if (strcmp(e->value, devname) == 0)
d58b3157 332 /* tags have already been read */
7755ca95
KZ
333 return 0;
334 }
335
6257e445
KZ
336 pr = blkid_new_probe_from_filename(devname);
337 if (!pr)
338 return -1;
7755ca95 339
6257e445
KZ
340 blkid_probe_enable_superblocks(pr, 1);
341 blkid_probe_set_superblocks_flags(pr,
8485e709
KZ
342 BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID |
343 BLKID_SUBLKS_TYPE);
7755ca95 344
6257e445
KZ
345 blkid_probe_enable_partitions(pr, 1);
346 blkid_probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS);
cff632af 347
82a2c160
KZ
348 rc = blkid_do_safeprobe(pr);
349 if (rc)
7755ca95
KZ
350 goto error;
351
83a78332 352 DBG(CACHE, ul_debugobj(cache, "reading tags for: %s", devname));
33eff02a 353
7755ca95
KZ
354 for (i = 0; i < ARRAY_SIZE(tags); i++) {
355 const char *data;
356 char *dev;
357
679f59dd 358 if (cache_find_tag_value(cache, devname, tags[i])) {
83a78332 359 DBG(CACHE, ul_debugobj(cache,
679f59dd
KZ
360 "\ntag %s already cached", tags[i]));
361 continue;
362 }
6257e445 363 if (blkid_probe_lookup_value(pr, blktags[i], &data, NULL))
7755ca95 364 continue;
7755ca95
KZ
365 dev = strdup(devname);
366 if (!dev)
367 goto error;
171b0fb4 368 if (cache_add_tag(cache, tags[i], data, dev,
2e67aee9 369 MNT_CACHE_TAGREAD)) {
7755ca95
KZ
370 free(dev);
371 goto error;
372 }
373 ntags++;
374 }
375
83a78332 376 DBG(CACHE, ul_debugobj(cache, "\tread %zd tags", ntags));
6257e445 377 blkid_free_probe(pr);
ba7232a1 378 return ntags ? 0 : 1;
7755ca95 379error:
6257e445 380 blkid_free_probe(pr);
82a2c160 381 return rc < 0 ? rc : -1;
7755ca95
KZ
382}
383
384/**
385 * mnt_cache_device_has_tag:
386 * @cache: paths cache
387 * @devname: path to the device
388 * @token: tag name (e.g "LABEL")
389 * @value: tag value
390 *
d58b3157 391 * Look up @cache to check if @tag+@value are associated with @devname.
7755ca95
KZ
392 *
393 * Returns: 1 on success or 0.
394 */
68164f6c 395int mnt_cache_device_has_tag(struct libmnt_cache *cache, const char *devname,
7755ca95
KZ
396 const char *token, const char *value)
397{
171b0fb4 398 const char *path = cache_find_tag(cache, token, value);
7755ca95 399
90cd46cb 400 if (path && devname && strcmp(path, devname) == 0)
7755ca95
KZ
401 return 1;
402 return 0;
403}
404
82a2c160
KZ
405static int __mnt_cache_find_tag_value(struct libmnt_cache *cache,
406 const char *devname, const char *token, char **data)
407{
408 int rc = 0;
409
410 if (!cache || !devname || !token || !data)
411 return -EINVAL;
412
413 rc = mnt_cache_read_tags(cache, devname);
414 if (rc)
415 return rc;
416
417 *data = cache_find_tag_value(cache, devname, token);
b48d80fb 418 return *data ? 0 : -1;
82a2c160
KZ
419}
420
ba7232a1
KZ
421/**
422 * mnt_cache_find_tag_value:
423 * @cache: cache for results
424 * @devname: device name
425 * @token: tag name ("LABEL" or "UUID")
426 *
427 * Returns: LABEL or UUID for the @devname or NULL in case of error.
428 */
68164f6c 429char *mnt_cache_find_tag_value(struct libmnt_cache *cache,
ba7232a1
KZ
430 const char *devname, const char *token)
431{
82a2c160 432 char *data = NULL;
ba7232a1 433
82a2c160
KZ
434 if (__mnt_cache_find_tag_value(cache, devname, token, &data) == 0)
435 return data;
436 return NULL;
ba7232a1
KZ
437}
438
8485e709
KZ
439/**
440 * mnt_get_fstype:
441 * @devname: device name
f58168ff 442 * @ambi: returns TRUE if probing result is ambivalent (optional argument)
8485e709
KZ
443 * @cache: cache for results or NULL
444 *
60dafc19 445 * Returns: filesystem type or NULL in case of error. The result has to be
8485e709
KZ
446 * deallocated by free() if @cache is NULL.
447 */
68164f6c 448char *mnt_get_fstype(const char *devname, int *ambi, struct libmnt_cache *cache)
8485e709
KZ
449{
450 blkid_probe pr;
451 const char *data;
452 char *type = NULL;
f58168ff 453 int rc;
8485e709 454
83a78332 455 DBG(CACHE, ul_debugobj(cache, "get %s FS type", devname));
c59cf20c 456
82a2c160
KZ
457 if (cache) {
458 char *val = NULL;
459 rc = __mnt_cache_find_tag_value(cache, devname, "TYPE", &val);
460 if (ambi)
461 *ambi = rc == -2 ? TRUE : FALSE;
462 return rc ? NULL : val;
463 }
8485e709 464
6257e445
KZ
465 /*
466 * no cache, probe directly
467 */
468 pr = blkid_new_probe_from_filename(devname);
469 if (!pr)
8485e709
KZ
470 return NULL;
471
472 blkid_probe_enable_superblocks(pr, 1);
8485e709
KZ
473 blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_TYPE);
474
f58168ff
KZ
475 rc = blkid_do_safeprobe(pr);
476
83a78332 477 DBG(CACHE, ul_debugobj(cache, "libblkid rc=%d", rc));
82a2c160 478
f58168ff 479 if (!rc && !blkid_probe_lookup_value(pr, "TYPE", &data, NULL))
8485e709
KZ
480 type = strdup(data);
481
f58168ff
KZ
482 if (ambi)
483 *ambi = rc == -2 ? TRUE : FALSE;
484
8485e709
KZ
485 blkid_free_probe(pr);
486 return type;
487}
488
0382ba32
ER
489static char *canonicalize_path_and_cache(const char *path,
490 struct libmnt_cache *cache)
491{
1b504263
SK
492 char *p;
493 char *key;
494 char *value;
0382ba32 495
8642cd7b 496 DBG(CACHE, ul_debugobj(cache, "canonicalize path %s", path));
0382ba32
ER
497 p = canonicalize_path(path);
498
499 if (p && cache) {
500 value = p;
501 key = strcmp(path, p) == 0 ? value : strdup(path);
502
503 if (!key || !value)
504 goto error;
505
506 if (cache_add_entry(cache, key, value,
507 MNT_CACHE_ISPATH))
508 goto error;
509 }
510
511 return p;
512error:
513 if (value != key)
514 free(value);
515 free(key);
516 return NULL;
517}
518
7755ca95
KZ
519/**
520 * mnt_resolve_path:
521 * @path: "native" path
522 * @cache: cache for results or NULL
523 *
2576b4e7
KZ
524 * Converts path:
525 * - to the absolute path
63de90d4 526 * - /dev/dm-N to /dev/mapper/name
2576b4e7 527 *
192c6aad 528 * Returns: absolute path or NULL in case of error. The result has to be
7755ca95
KZ
529 * deallocated by free() if @cache is NULL.
530 */
68164f6c 531char *mnt_resolve_path(const char *path, struct libmnt_cache *cache)
7755ca95
KZ
532{
533 char *p = NULL;
7755ca95 534
83a78332 535 /*DBG(CACHE, ul_debugobj(cache, "resolving path %s", path));*/
c59cf20c 536
7755ca95
KZ
537 if (!path)
538 return NULL;
539 if (cache)
171b0fb4 540 p = (char *) cache_find_path(cache, path);
0382ba32
ER
541 if (!p)
542 p = canonicalize_path_and_cache(path, cache);
7755ca95 543
0382ba32
ER
544 return p;
545}
7755ca95 546
0382ba32
ER
547/**
548 * mnt_resolve_target:
549 * @path: "native" path, a potential mount point
550 * @cache: cache for results or NULL.
551 *
552 * Like mnt_resolve_path(), unless @cache is not NULL and
553 * mnt_cache_set_targets(cache, mtab) was called: if @path is found in the
554 * cached @mtab and the matching entry was provided by the kernel, assume that
0cf83127 555 * @path is already canonicalized. By avoiding a call to realpath(2) on
0382ba32
ER
556 * known mount points, there is a lower risk of stepping on a stale mount
557 * point, which can result in an application freeze. This is also faster in
558 * general, as stat(2) on a mount point is slower than on a regular file.
559 *
560 * Returns: absolute path or NULL in case of error. The result has to be
561 * deallocated by free() if @cache is NULL.
562 */
563char *mnt_resolve_target(const char *path, struct libmnt_cache *cache)
564{
565 char *p = NULL;
566
567 /*DBG(CACHE, ul_debugobj(cache, "resolving target %s", path));*/
568
569 if (!cache || !cache->mtab)
570 return mnt_resolve_path(path, cache);
571
572 p = (char *) cache_find_path(cache, path);
573 if (p)
574 return p;
575 else {
576 struct libmnt_iter itr;
577 struct libmnt_fs *fs = NULL;
7755ca95 578
0382ba32
ER
579 mnt_reset_iter(&itr, MNT_ITER_BACKWARD);
580 while (mnt_table_next_fs(cache->mtab, &itr, &fs) == 0) {
7755ca95 581
0382ba32
ER
582 if (!mnt_fs_is_kernel(fs)
583 || mnt_fs_is_swaparea(fs)
584 || !mnt_fs_streq_target(fs, path))
585 continue;
586
587 p = strdup(path);
588 if (!p)
589 return NULL; /* ENOMEM */
590
591 if (cache_add_entry(cache, p, p, MNT_CACHE_ISPATH)) {
592 free(p);
593 return NULL; /* ENOMEM */
594 }
595 break;
7755ca95
KZ
596 }
597 }
598
0382ba32
ER
599 if (!p)
600 p = canonicalize_path_and_cache(path, cache);
7755ca95 601 return p;
7755ca95
KZ
602}
603
2576b4e7
KZ
604/**
605 * mnt_pretty_path:
606 * @path: any path
607 * @cache: NULL or pointer to the cache
608 *
609 * Converts path:
610 * - to the absolute path
63de90d4 611 * - /dev/dm-N to /dev/mapper/name
2576b4e7
KZ
612 * - /dev/loopN to the loop backing filename
613 * - empty path (NULL) to 'none'
614 *
d58b3157 615 * Returns: newly allocated string with path, result always has to be deallocated
2576b4e7
KZ
616 * by free().
617 */
618char *mnt_pretty_path(const char *path, struct libmnt_cache *cache)
619{
620 char *pretty = mnt_resolve_path(path, cache);
621
622 if (!pretty)
623 return strdup("none");
624
e624bc55 625#ifdef __linux__
2576b4e7
KZ
626 /* users assume backing file name rather than /dev/loopN in
627 * output if the device has been initialized by mount(8).
628 */
629 if (strncmp(pretty, "/dev/loop", 9) == 0) {
630 struct loopdev_cxt lc;
631
defa0710
KZ
632 if (loopcxt_init(&lc, 0) || loopcxt_set_device(&lc, pretty))
633 goto done;
2576b4e7
KZ
634
635 if (loopcxt_is_autoclear(&lc)) {
636 char *tmp = loopcxt_get_backing_file(&lc);
637 if (tmp) {
af865643 638 loopcxt_deinit(&lc);
2576b4e7
KZ
639 if (!cache)
640 free(pretty); /* not cached, deallocate */
641 return tmp; /* return backing file */
642 }
643 }
644 loopcxt_deinit(&lc);
645
646 }
e624bc55 647#endif
2576b4e7 648
defa0710 649done:
2576b4e7
KZ
650 /* don't return pointer to the cache, allocate a new string */
651 return cache ? strdup(pretty) : pretty;
652}
653
7755ca95
KZ
654/**
655 * mnt_resolve_tag:
656 * @token: tag name
657 * @value: tag value
658 * @cache: for results or NULL
659 *
192c6aad 660 * Returns: device name or NULL in case of error. The result has to be
7755ca95
KZ
661 * deallocated by free() if @cache is NULL.
662 */
68164f6c
KZ
663char *mnt_resolve_tag(const char *token, const char *value,
664 struct libmnt_cache *cache)
7755ca95
KZ
665{
666 char *p = NULL;
667
83a78332 668 /*DBG(CACHE, ul_debugobj(cache, "resolving tag token=%s value=%s",
0983b5f7 669 token, value));*/
c59cf20c 670
7755ca95
KZ
671 if (!token || !value)
672 return NULL;
673
674 if (cache)
171b0fb4 675 p = (char *) cache_find_tag(cache, token, value);
7755ca95
KZ
676
677 if (!p) {
678 /* returns newly allocated string */
679 p = blkid_evaluate_tag(token, value, cache ? &cache->bc : NULL);
680
681 if (p && cache &&
171b0fb4 682 cache_add_tag(cache, token, value, p, 0))
7755ca95
KZ
683 goto error;
684 }
685
7755ca95
KZ
686 return p;
687error:
688 free(p);
689 return NULL;
690}
691
692
693
694/**
695 * mnt_resolve_spec:
696 * @spec: path or tag
697 * @cache: paths cache
698 *
192c6aad 699 * Returns: canonicalized path or NULL. The result has to be
3fca8422 700 * deallocated by free() if @cache is NULL.
7755ca95 701 */
68164f6c 702char *mnt_resolve_spec(const char *spec, struct libmnt_cache *cache)
7755ca95
KZ
703{
704 char *cn = NULL;
2c6b25f0 705 char *t = NULL, *v = NULL;
7755ca95
KZ
706
707 if (!spec)
708 return NULL;
709
2c6b25f0
KZ
710 if (blkid_parse_tag_string(spec, &t, &v) == 0 && mnt_valid_tagname(t))
711 cn = mnt_resolve_tag(t, v, cache);
712 else
7755ca95
KZ
713 cn = mnt_resolve_path(spec, cache);
714
2c6b25f0
KZ
715 free(t);
716 free(v);
7755ca95
KZ
717 return cn;
718}
719
720
721#ifdef TEST_PROGRAM
722
5fde1d9f 723static int test_resolve_path(struct libmnt_test *ts, int argc, char *argv[])
7755ca95
KZ
724{
725 char line[BUFSIZ];
68164f6c 726 struct libmnt_cache *cache;
7755ca95
KZ
727
728 cache = mnt_new_cache();
729 if (!cache)
abc3d154 730 return -ENOMEM;
7755ca95
KZ
731
732 while(fgets(line, sizeof(line), stdin)) {
733 size_t sz = strlen(line);
734 char *p;
735
9d670a2a 736 if (sz > 0 && line[sz - 1] == '\n')
7755ca95
KZ
737 line[sz - 1] = '\0';
738
739 p = mnt_resolve_path(line, cache);
740 printf("%s : %s\n", line, p);
741 }
0105691d 742 mnt_unref_cache(cache);
7755ca95
KZ
743 return 0;
744}
745
5fde1d9f 746static int test_resolve_spec(struct libmnt_test *ts, int argc, char *argv[])
7755ca95
KZ
747{
748 char line[BUFSIZ];
68164f6c 749 struct libmnt_cache *cache;
7755ca95
KZ
750
751 cache = mnt_new_cache();
752 if (!cache)
abc3d154 753 return -ENOMEM;
7755ca95
KZ
754
755 while(fgets(line, sizeof(line), stdin)) {
756 size_t sz = strlen(line);
757 char *p;
758
9d670a2a 759 if (sz > 0 && line[sz - 1] == '\n')
7755ca95
KZ
760 line[sz - 1] = '\0';
761
762 p = mnt_resolve_spec(line, cache);
763 printf("%s : %s\n", line, p);
764 }
0105691d 765 mnt_unref_cache(cache);
7755ca95
KZ
766 return 0;
767}
768
5fde1d9f 769static int test_read_tags(struct libmnt_test *ts, int argc, char *argv[])
7755ca95
KZ
770{
771 char line[BUFSIZ];
68164f6c 772 struct libmnt_cache *cache;
3d660e74 773 size_t i;
7755ca95
KZ
774
775 cache = mnt_new_cache();
776 if (!cache)
abc3d154 777 return -ENOMEM;
7755ca95
KZ
778
779 while(fgets(line, sizeof(line), stdin)) {
780 size_t sz = strlen(line);
2c6b25f0 781 char *t = NULL, *v = NULL;
7755ca95 782
9d670a2a 783 if (sz > 0 && line[sz - 1] == '\n')
7755ca95
KZ
784 line[sz - 1] = '\0';
785
8485e709
KZ
786 if (!strcmp(line, "quit"))
787 break;
788
7755ca95
KZ
789 if (*line == '/') {
790 if (mnt_cache_read_tags(cache, line) < 0)
26e42d81 791 fprintf(stderr, "%s: read tags failed\n", line);
7755ca95 792
2c6b25f0 793 } else if (blkid_parse_tag_string(line, &t, &v) == 0) {
7755ca95
KZ
794 const char *cn = NULL;
795
2c6b25f0
KZ
796 if (mnt_valid_tagname(t))
797 cn = cache_find_tag(cache, t, v);
798 free(t);
799 free(v);
7755ca95 800
7755ca95
KZ
801 if (cn)
802 printf("%s: %s\n", line, cn);
803 else
804 printf("%s: not cached\n", line);
805 }
806 }
8485e709
KZ
807
808 for (i = 0; i < cache->nents; i++) {
809 struct mnt_cache_entry *e = &cache->ents[i];
810 if (!(e->flag & MNT_CACHE_ISTAG))
811 continue;
812
8eef6df7
KZ
813 printf("%15s : %5s : %s\n", e->value, e->key,
814 e->key + strlen(e->key) + 1);
8485e709
KZ
815 }
816
0105691d 817 mnt_unref_cache(cache);
7755ca95
KZ
818 return 0;
819
820}
821
822int main(int argc, char *argv[])
823{
68164f6c 824 struct libmnt_test ts[] = {
7755ca95
KZ
825 { "--resolve-path", test_resolve_path, " resolve paths from stdin" },
826 { "--resolve-spec", test_resolve_spec, " evaluate specs from stdin" },
8485e709 827 { "--read-tags", test_read_tags, " read devname or TAG from stdin (\"quit\" to exit)" },
7755ca95
KZ
828 { NULL }
829 };
830
831 return mnt_run_test(ts, argc, argv);
832}
833#endif