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