]> git.ipfire.org Git - thirdparty/util-linux.git/blame - shlibs/mount/src/tab.c
libmount: don't prepare update if syscall failed
[thirdparty/util-linux.git] / shlibs / mount / src / tab.c
CommitLineData
6bd8b7a7 1/*
192c6aad 2 * Copyright (C) 2008-2010 Karel Zak <kzak@redhat.com>
6bd8b7a7
KZ
3 *
4 * This file may be redistributed under the terms of the
5 * GNU Lesser General Public License.
192c6aad
KZ
6 */
7
8/**
9 * SECTION: tab
0f32f1e2 10 * @title: Table of filesystems
192c6aad
KZ
11 * @short_description: container for entries from fstab/mtab/mountinfo
12 *
6bd8b7a7 13 *
68164f6c 14 * Note that mnt_table_find_* functions are mount(8) compatible. These functions
192c6aad
KZ
15 * try to found an entry in more iterations where the first attempt is always
16 * based on comparison with unmodified (non-canonicalized or un-evaluated)
17 * paths or tags. For example fstab with two entries:
3d735589
KZ
18 * <informalexample>
19 * <programlisting>
192c6aad
KZ
20 * LABEL=foo /foo auto rw
21 * /dev/foo /foo auto rw
3d735589
KZ
22 * </programlisting>
23 * </informalexample>
6bd8b7a7 24 *
192c6aad 25 * where both lines are used for the *same* device, then
3d735589
KZ
26 * <informalexample>
27 * <programlisting>
68164f6c 28 * mnt_table_find_source(tb, "/dev/foo", &fs);
3d735589
KZ
29 * </programlisting>
30 * </informalexample>
192c6aad 31 * will returns the second line, and
3d735589
KZ
32 * <informalexample>
33 * <programlisting>
68164f6c 34 * mnt_table_find_source(tb, "LABEL=foo", &fs);
3d735589
KZ
35 * </programlisting>
36 * </informalexample>
192c6aad 37 * will returns the first entry, and
3d735589
KZ
38 * <informalexample>
39 * <programlisting>
68164f6c 40 * mnt_table_find_source(tb, "UUID=anyuuid", &fs);
3d735589
KZ
41 * </programlisting>
42 * </informalexample>
192c6aad 43 * will returns the first entry (if UUID matches with the device).
6bd8b7a7
KZ
44 */
45
46#include <string.h>
47#include <stdlib.h>
48#include <ctype.h>
3fca8422 49#include <errno.h>
6bd8b7a7
KZ
50#include <limits.h>
51#include <sys/types.h>
52#include <sys/stat.h>
53#include <unistd.h>
8e368761 54#include <blkid.h>
6bd8b7a7
KZ
55
56#include "nls.h"
57#include "mountP.h"
4951f9b3 58#include "c.h"
6bd8b7a7
KZ
59
60/**
68164f6c 61 * mnt_new_table:
6bd8b7a7 62 *
68164f6c 63 * The tab is a container for struct libmnt_fs entries that usually represents a fstab,
6bd8b7a7
KZ
64 * mtab or mountinfo file from your system.
65 *
68164f6c 66 * See also mnt_table_parse_file().
6bd8b7a7 67 *
192c6aad 68 * Returns: newly allocated tab struct.
6bd8b7a7 69 */
68164f6c 70struct libmnt_table *mnt_new_table(void)
6bd8b7a7 71{
68164f6c 72 struct libmnt_table *tb = NULL;
6bd8b7a7 73
68164f6c 74 tb = calloc(1, sizeof(*tb));
6bd8b7a7 75 if (!tb)
9ed7507c
KZ
76 return NULL;
77
3f31a959 78 DBG(TAB, mnt_debug_h(tb, "alloc"));
6bd8b7a7 79
6bd8b7a7
KZ
80 INIT_LIST_HEAD(&tb->ents);
81 return tb;
6bd8b7a7
KZ
82}
83
84/**
68164f6c 85 * mnt_free_table:
3d735589 86 * @tb: tab pointer
6bd8b7a7
KZ
87 *
88 * Deallocates tab struct and all entries.
89 */
68164f6c 90void mnt_free_table(struct libmnt_table *tb)
6bd8b7a7
KZ
91{
92 if (!tb)
93 return;
6bd8b7a7 94
3f31a959
KZ
95 DBG(TAB, mnt_debug_h(tb, "free"));
96
6bd8b7a7 97 while (!list_empty(&tb->ents)) {
68164f6c
KZ
98 struct libmnt_fs *fs = list_entry(tb->ents.next,
99 struct libmnt_fs, ents);
6bd8b7a7
KZ
100 mnt_free_fs(fs);
101 }
102
103 free(tb);
104}
105
106/**
68164f6c 107 * mnt_table_get_nents:
6bd8b7a7
KZ
108 * @tb: pointer to tab
109 *
192c6aad 110 * Returns: number of valid entries in tab.
6bd8b7a7 111 */
68164f6c 112int mnt_table_get_nents(struct libmnt_table *tb)
6bd8b7a7
KZ
113{
114 assert(tb);
115 return tb ? tb->nents : 0;
116}
117
118/**
68164f6c 119 * mnt_table_set_cache:
6bd8b7a7 120 * @tb: pointer to tab
68164f6c 121 * @mpc: pointer to struct libmnt_cache instance
6bd8b7a7
KZ
122 *
123 * Setups a cache for canonicalized paths and evaluated tags (LABEL/UUID). The
68164f6c 124 * cache is recommended for mnt_table_find_*() functions.
6bd8b7a7
KZ
125 *
126 * The cache could be shared between more tabs. Be careful when you share the
127 * same cache between more threads -- currently the cache does not provide any
128 * locking method.
129 *
130 * See also mnt_new_cache().
131 *
59ae0ddd 132 * Returns: 0 on success or negative number in case of error.
6bd8b7a7 133 */
68164f6c 134int mnt_table_set_cache(struct libmnt_table *tb, struct libmnt_cache *mpc)
6bd8b7a7
KZ
135{
136 assert(tb);
137 if (!tb)
59ae0ddd 138 return -EINVAL;
6bd8b7a7
KZ
139 tb->cache = mpc;
140 return 0;
141}
142
143/**
68164f6c 144 * mnt_table_get_cache:
6bd8b7a7
KZ
145 * @tb: pointer to tab
146 *
68164f6c 147 * Returns: pointer to struct libmnt_cache instance or NULL.
6bd8b7a7 148 */
68164f6c 149struct libmnt_cache *mnt_table_get_cache(struct libmnt_table *tb)
6bd8b7a7
KZ
150{
151 assert(tb);
152 return tb ? tb->cache : NULL;
153}
154
6bd8b7a7 155/**
68164f6c 156 * mnt_table_add_fs:
6bd8b7a7
KZ
157 * @tb: tab pointer
158 * @fs: new entry
159 *
160 * Adds a new entry to tab.
161 *
59ae0ddd 162 * Returns: 0 on success or negative number in case of error.
6bd8b7a7 163 */
68164f6c 164int mnt_table_add_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
6bd8b7a7
KZ
165{
166 assert(tb);
167 assert(fs);
168
169 if (!tb || !fs)
59ae0ddd 170 return -EINVAL;
6bd8b7a7
KZ
171
172 list_add_tail(&fs->ents, &tb->ents);
173
3f31a959
KZ
174 DBG(TAB, mnt_debug_h(tb, "add entry: %s %s",
175 mnt_fs_get_source(fs), mnt_fs_get_target(fs)));
911238af 176 tb->nents++;
6bd8b7a7
KZ
177 return 0;
178}
179
180/**
68164f6c 181 * mnt_table_remove_fs:
6bd8b7a7
KZ
182 * @tb: tab pointer
183 * @fs: new entry
184 *
59ae0ddd 185 * Returns: 0 on success or negative number in case of error.
6bd8b7a7 186 */
68164f6c 187int mnt_table_remove_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
6bd8b7a7
KZ
188{
189 assert(tb);
190 assert(fs);
191
192 if (!tb || !fs)
59ae0ddd 193 return -EINVAL;
6bd8b7a7 194 list_del(&fs->ents);
911238af 195 tb->nents--;
6bd8b7a7
KZ
196 return 0;
197}
198
26b4f9e4 199/**
68164f6c 200 * mnt_table_get_root_fs:
26b4f9e4
KZ
201 * @tb: mountinfo file (/proc/self/mountinfo)
202 * @root: returns pointer to the root filesystem (/)
203 *
204 * Returns: 0 on success or -1 case of error.
205 */
68164f6c 206int mnt_table_get_root_fs(struct libmnt_table *tb, struct libmnt_fs **root)
26b4f9e4 207{
68164f6c
KZ
208 struct libmnt_iter itr;
209 struct libmnt_fs *fs;
26b4f9e4
KZ
210 int root_id = 0;
211
212 assert(tb);
213 assert(root);
214
215 if (!tb || !root)
59ae0ddd 216 return -EINVAL;
26b4f9e4 217
0ccfc837 218 DBG(TAB, mnt_debug_h(tb, "lookup root fs"));
20aae9d3 219
26b4f9e4 220 mnt_reset_iter(&itr, MNT_ITER_FORWARD);
68164f6c 221 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
26b4f9e4
KZ
222 int id = mnt_fs_get_parent_id(fs);
223 if (!id)
224 break; /* @tab is not mountinfo file? */
225
226 if (!*root || id < root_id) {
227 *root = fs;
228 root_id = id;
229 }
230 }
231
59ae0ddd 232 return root_id ? 0 : -EINVAL;
26b4f9e4
KZ
233}
234
235/**
68164f6c 236 * mnt_table_next_child_fs:
26b4f9e4 237 * @tb: mountinfo file (/proc/self/mountinfo)
3d735589 238 * @itr: iterator
26b4f9e4
KZ
239 * @parent: parental FS
240 * @chld: returns the next child filesystem
241 *
242 * Note that filesystems are returned in the order how was mounted (according to
243 * IDs in /proc/self/mountinfo).
244 *
59ae0ddd 245 * Returns: 0 on success, negative number in case of error or 1 at end of list.
26b4f9e4 246 */
68164f6c
KZ
247int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
248 struct libmnt_fs *parent, struct libmnt_fs **chld)
26b4f9e4 249{
68164f6c 250 struct libmnt_fs *fs;
26b4f9e4
KZ
251 int parent_id, lastchld_id = 0, chld_id = 0;
252
253 if (!tb || !itr || !parent)
59ae0ddd 254 return -EINVAL;
26b4f9e4 255
3f31a959
KZ
256 DBG(TAB, mnt_debug_h(tb, "lookup next child of %s",
257 mnt_fs_get_target(parent)));
20aae9d3 258
26b4f9e4
KZ
259 parent_id = mnt_fs_get_id(parent);
260 if (!parent_id)
59ae0ddd 261 return -EINVAL;
26b4f9e4
KZ
262
263 /* get ID of the previously returned child */
264 if (itr->head && itr->p != itr->head) {
68164f6c 265 MNT_ITER_ITERATE(itr, fs, struct libmnt_fs, ents);
26b4f9e4
KZ
266 lastchld_id = mnt_fs_get_id(fs);
267 }
268
269 *chld = NULL;
270
271 mnt_reset_iter(itr, MNT_ITER_FORWARD);
68164f6c 272 while(mnt_table_next_fs(tb, itr, &fs) == 0) {
26b4f9e4
KZ
273 int id;
274
275 if (mnt_fs_get_parent_id(fs) != parent_id)
276 continue;
277
278 id = mnt_fs_get_id(fs);
279
280 if ((!lastchld_id || id > lastchld_id) &&
281 (!*chld || id < chld_id)) {
282 *chld = fs;
283 chld_id = id;
284 }
285 }
286
287 if (!chld_id)
288 return 1; /* end of iterator */
289
290 /* set the iterator to the @chld for the next call */
68164f6c 291 mnt_table_set_iter(tb, itr, *chld);
26b4f9e4
KZ
292
293 return 0;
294}
295
6bd8b7a7 296/**
68164f6c 297 * mnt_table_next_fs:
6bd8b7a7
KZ
298 * @tb: tab pointer
299 * @itr: iterator
300 * @fs: returns the next tab entry
301 *
59ae0ddd 302 * Returns: 0 on success, negative number in case of error or 1 at end of list.
6bd8b7a7 303 *
0f32f1e2 304 * Example:
3d735589
KZ
305 * <informalexample>
306 * <programlisting>
68164f6c 307 * while(mnt_table_next_fs(tb, itr, &fs) == 0) {
6bd8b7a7
KZ
308 * const char *dir = mnt_fs_get_target(fs);
309 * printf("mount point: %s\n", dir);
310 * }
68164f6c 311 * mnt_free_table(fi);
3d735589
KZ
312 * </programlisting>
313 * </informalexample>
0f32f1e2
KZ
314 *
315 * lists all mountpoints from fstab in backward order.
6bd8b7a7 316 */
68164f6c 317int mnt_table_next_fs(struct libmnt_table *tb, struct libmnt_iter *itr, struct libmnt_fs **fs)
6bd8b7a7 318{
59ae0ddd 319 int rc = 1;
3fca8422 320
6bd8b7a7
KZ
321 assert(tb);
322 assert(itr);
323 assert(fs);
324
325 if (!tb || !itr || !fs)
59ae0ddd 326 return -EINVAL;
0532ba1d
KZ
327 *fs = NULL;
328
6bd8b7a7
KZ
329 if (!itr->head)
330 MNT_ITER_INIT(itr, &tb->ents);
331 if (itr->p != itr->head) {
68164f6c 332 MNT_ITER_ITERATE(itr, *fs, struct libmnt_fs, ents);
3fca8422 333 rc = 0;
6bd8b7a7
KZ
334 }
335
3fca8422
KZ
336 return rc;
337}
338
339/**
68164f6c 340 * mnt_table_find_next_fs:
3fca8422
KZ
341 * @tb: table
342 * @itr: iterator
343 * @match_func: function returns 1 or 0
3d735589 344 * @userdata: extra data for match_func
3fca8422
KZ
345 * @fs: returns pointer to the next matching table entry
346 *
347 * This function allows search in @tb.
348 *
59ae0ddd 349 * Returns: negative number in case of error, 1 at end of table or 0 o success.
3fca8422 350 */
68164f6c
KZ
351int mnt_table_find_next_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
352 int (*match_func)(struct libmnt_fs *, void *), void *userdata,
353 struct libmnt_fs **fs)
3fca8422
KZ
354{
355 if (!tb || !itr || !fs || !match_func)
59ae0ddd 356 return -EINVAL;
3fca8422 357
0ccfc837 358 DBG(TAB, mnt_debug_h(tb, "lookup next fs"));
20aae9d3 359
3fca8422
KZ
360 if (!itr->head)
361 MNT_ITER_INIT(itr, &tb->ents);
362
363 do {
364 if (itr->p != itr->head)
68164f6c 365 MNT_ITER_ITERATE(itr, *fs, struct libmnt_fs, ents);
3fca8422
KZ
366 else
367 break; /* end */
368
3fca8422
KZ
369 if (match_func(*fs, userdata))
370 return 0;
371 } while(1);
372
26b4f9e4 373 *fs = NULL;
6bd8b7a7
KZ
374 return 1;
375}
376
377/**
68164f6c 378 * mnt_table_set_iter:
6bd8b7a7
KZ
379 * @tb: tab pointer
380 * @itr: iterator
381 * @fs: tab entry
382 *
383 * Sets @iter to the position of @fs in the file @tb.
384 *
59ae0ddd 385 * Returns: 0 on success, negative number in case of error.
6bd8b7a7 386 */
68164f6c 387int mnt_table_set_iter(struct libmnt_table *tb, struct libmnt_iter *itr, struct libmnt_fs *fs)
6bd8b7a7
KZ
388{
389 assert(tb);
390 assert(itr);
391 assert(fs);
392
393 if (!tb || !itr || !fs)
59ae0ddd 394 return -EINVAL;
6bd8b7a7
KZ
395
396 MNT_ITER_INIT(itr, &tb->ents);
397 itr->p = &fs->ents;
398
399 return 0;
400}
401
402/**
68164f6c 403 * mnt_table_find_target:
6bd8b7a7
KZ
404 * @tb: tab pointer
405 * @path: mountpoint directory
406 * @direction: MNT_ITER_{FORWARD,BACKWARD}
407 *
408 * Try to lookup an entry in given tab, possible are three iterations, first
409 * with @path, second with realpath(@path) and third with realpath(@path)
410 * against realpath(fs->target). The 2nd and 3rd iterations are not performed
68164f6c 411 * when @tb cache is not set (see mnt_table_set_cache()).
6bd8b7a7 412 *
192c6aad 413 * Returns: a tab entry or NULL.
6bd8b7a7 414 */
68164f6c 415struct libmnt_fs *mnt_table_find_target(struct libmnt_table *tb, const char *path, int direction)
6bd8b7a7 416{
68164f6c
KZ
417 struct libmnt_iter itr;
418 struct libmnt_fs *fs = NULL;
6bd8b7a7
KZ
419 char *cn;
420
421 assert(tb);
422 assert(path);
423
59ae0ddd
KZ
424 if (!tb || !path)
425 return NULL;
426
3f31a959 427 DBG(TAB, mnt_debug_h(tb, "lookup target: %s", path));
6bd8b7a7
KZ
428
429 /* native @target */
430 mnt_reset_iter(&itr, direction);
68164f6c 431 while(mnt_table_next_fs(tb, &itr, &fs) == 0)
6bd8b7a7
KZ
432 if (fs->target && strcmp(fs->target, path) == 0)
433 return fs;
434
435 if (!tb->cache || !(cn = mnt_resolve_path(path, tb->cache)))
436 return NULL;
437
68164f6c 438 /* canonicalized paths in struct libmnt_table */
6bd8b7a7 439 mnt_reset_iter(&itr, direction);
68164f6c 440 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
6bd8b7a7
KZ
441 if (fs->target && strcmp(fs->target, cn) == 0)
442 return fs;
443 }
444
68164f6c 445 /* non-canonicaled path in struct libmnt_table */
6bd8b7a7 446 mnt_reset_iter(&itr, direction);
68164f6c 447 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
6bd8b7a7 448 char *p;
9dd75aa6
KZ
449
450 if (!fs->target || !(fs->flags & MNT_FS_SWAP) ||
451 (*fs->target == '/' && *(fs->target + 1) == '\0'))
6bd8b7a7 452 continue;
9dd75aa6 453
6bd8b7a7
KZ
454 p = mnt_resolve_path(fs->target, tb->cache);
455 if (strcmp(cn, p) == 0)
456 return fs;
457 }
458 return NULL;
459}
460
461/**
68164f6c 462 * mnt_table_find_srcpath:
6bd8b7a7
KZ
463 * @tb: tab pointer
464 * @path: source path (devname or dirname)
465 * @direction: MNT_ITER_{FORWARD,BACKWARD}
466 *
467 * Try to lookup an entry in given tab, possible are four iterations, first
468 * with @path, second with realpath(@path), third with tags (LABEL, UUID, ..)
469 * from @path and fourth with realpath(@path) against realpath(entry->srcpath).
470 *
471 * The 2nd, 3rd and 4th iterations are not performed when @tb cache is not
68164f6c 472 * set (see mnt_table_set_cache()).
6bd8b7a7 473 *
192c6aad 474 * Returns: a tab entry or NULL.
6bd8b7a7 475 */
68164f6c 476struct libmnt_fs *mnt_table_find_srcpath(struct libmnt_table *tb, const char *path, int direction)
6bd8b7a7 477{
68164f6c
KZ
478 struct libmnt_iter itr;
479 struct libmnt_fs *fs = NULL;
6bd8b7a7
KZ
480 int ntags = 0;
481 char *cn;
482 const char *p;
483
484 assert(tb);
485 assert(path);
486
3f31a959 487 DBG(TAB, mnt_debug_h(tb, "lookup srcpath: %s", path));
6bd8b7a7
KZ
488
489 /* native paths */
490 mnt_reset_iter(&itr, direction);
68164f6c 491 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
6bd8b7a7
KZ
492 p = mnt_fs_get_srcpath(fs);
493 if (p && strcmp(p, path) == 0)
494 return fs;
495 if (!p)
496 /* mnt_fs_get_srcpath() returs nothing, it's TAG */
497 ntags++;
498 }
499
500 if (!tb->cache || !(cn = mnt_resolve_path(path, tb->cache)))
501 return NULL;
502
68164f6c
KZ
503 /* canonicalized paths in struct libmnt_table */
504 if (ntags < mnt_table_get_nents(tb)) {
6bd8b7a7 505 mnt_reset_iter(&itr, direction);
68164f6c 506 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
6bd8b7a7
KZ
507 p = mnt_fs_get_srcpath(fs);
508 if (p && strcmp(p, cn) == 0)
509 return fs;
510 }
511 }
512
513 /* evaluated tag */
3fca8422 514 if (ntags) {
ba7232a1
KZ
515 int rc = mnt_cache_read_tags(tb->cache, cn);
516
6bd8b7a7 517 mnt_reset_iter(&itr, direction);
6bd8b7a7 518
ba7232a1 519 if (rc == 0) {
3fca8422 520 /* @path's TAGs are in the cache */
68164f6c 521 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
3fca8422 522 const char *t, *v;
6bd8b7a7 523
3fca8422
KZ
524 if (mnt_fs_get_tag(fs, &t, &v))
525 continue;
526
527 if (mnt_cache_device_has_tag(tb->cache, cn, t, v))
528 return fs;
529 }
ba7232a1 530 } else if (rc < 0 && errno == EACCES) {
3fca8422
KZ
531 /* @path is unaccessible, try evaluate all TAGs in @tb
532 * by udev symlinks -- this could be expensive on systems
533 * with huge fstab/mtab */
68164f6c 534 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
3fca8422
KZ
535 const char *t, *v, *x;
536 if (mnt_fs_get_tag(fs, &t, &v))
537 continue;
538 x = mnt_resolve_tag(t, v, tb->cache);
539 if (x && !strcmp(x, cn))
540 return fs;
541 }
6bd8b7a7
KZ
542 }
543 }
544
68164f6c
KZ
545 /* non-canonicalized paths in struct libmnt_table */
546 if (ntags <= mnt_table_get_nents(tb)) {
6bd8b7a7 547 mnt_reset_iter(&itr, direction);
68164f6c 548 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
9dd75aa6
KZ
549 if (fs->flags & (MNT_FS_NET | MNT_FS_PSEUDO))
550 continue;
6bd8b7a7
KZ
551 p = mnt_fs_get_srcpath(fs);
552 if (p)
553 p = mnt_resolve_path(p, tb->cache);
554 if (p && strcmp(cn, p) == 0)
555 return fs;
556 }
557 }
558
559 return NULL;
560}
561
562
563/**
68164f6c 564 * mnt_table_find_tag:
6bd8b7a7
KZ
565 * @tb: tab pointer
566 * @tag: tag name (e.g "LABEL", "UUID", ...)
567 * @val: tag value
568 * @direction: MNT_ITER_{FORWARD,BACKWARD}
569 *
570 * Try to lookup an entry in given tab, first attempt is lookup by @tag and
571 * @val, for the second attempt the tag is evaluated (converted to the device
68164f6c
KZ
572 * name) and mnt_table_find_srcpath() is preformed. The second attempt is not
573 * performed when @tb cache is not set (see mnt_table_set_cache()).
6bd8b7a7 574
192c6aad 575 * Returns: a tab entry or NULL.
6bd8b7a7 576 */
68164f6c 577struct libmnt_fs *mnt_table_find_tag(struct libmnt_table *tb, const char *tag,
6bd8b7a7
KZ
578 const char *val, int direction)
579{
68164f6c
KZ
580 struct libmnt_iter itr;
581 struct libmnt_fs *fs = NULL;
6bd8b7a7
KZ
582
583 assert(tb);
584 assert(tag);
585 assert(val);
586
587 if (!tb || !tag || !val)
588 return NULL;
589
3f31a959 590 DBG(TAB, mnt_debug_h(tb, "lookup by TAG: %s %s", tag, val));
6bd8b7a7
KZ
591
592 /* look up by TAG */
593 mnt_reset_iter(&itr, direction);
68164f6c 594 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
6bd8b7a7
KZ
595 if (fs->tagname && fs->tagval &&
596 strcmp(fs->tagname, tag) == 0 &&
597 strcmp(fs->tagval, val) == 0)
598 return fs;
599 }
600
601 if (tb->cache) {
602 /* look up by device name */
603 char *cn = mnt_resolve_tag(tag, val, tb->cache);
604 if (cn)
68164f6c 605 return mnt_table_find_srcpath(tb, cn, direction);
6bd8b7a7
KZ
606 }
607 return NULL;
608}
609
610/**
68164f6c 611 * mnt_table_find_source:
6bd8b7a7
KZ
612 * @tb: tab pointer
613 * @source: TAG or path
3d735589 614 * @direction: MNT_ITER_{FORWARD,BACKWARD}
6bd8b7a7 615 *
68164f6c 616 * This is high-level API for mnt_table_find_{srcpath,tag}. You needn't to care
6bd8b7a7 617 * about @source format (device, LABEL, UUID, ...). This function parses @source
68164f6c 618 * and calls mnt_table_find_tag() or mnt_table_find_srcpath().
6bd8b7a7 619 *
192c6aad 620 * Returns: a tab entry or NULL.
6bd8b7a7 621 */
68164f6c 622struct libmnt_fs *mnt_table_find_source(struct libmnt_table *tb, const char *source, int direction)
6bd8b7a7 623{
68164f6c 624 struct libmnt_fs *fs = NULL;
6bd8b7a7
KZ
625
626 assert(tb);
627 assert(source);
628
629 if (!tb || !source)
630 return NULL;
631
3f31a959 632 DBG(TAB, mnt_debug_h(tb, "lookup SOURCE: %s", source));
6bd8b7a7
KZ
633
634 if (strchr(source, '=')) {
635 char *tag, *val;
636
637 if (blkid_parse_tag_string(source, &tag, &val) == 0) {
638
68164f6c 639 fs = mnt_table_find_tag(tb, tag, val, direction);
6bd8b7a7
KZ
640
641 free(tag);
642 free(val);
643 }
644 } else
68164f6c 645 fs = mnt_table_find_srcpath(tb, source, direction);
6bd8b7a7
KZ
646
647 return fs;
648}
649
059c696f 650/**
68164f6c 651 * mnt_table_find_pair
059c696f
KZ
652 * @tb: tab pointer
653 * @source: TAG or path
654 * @target: mountpoint
655 * @direction: MNT_ITER_{FORWARD,BACKWARD}
656 *
657 * This function is implemented by mnt_fs_match_source() and
658 * mnt_fs_match_target() functions. It means that this is more expensive that
68164f6c 659 * others mnt_table_find_* function, because every @tab entry is fully evaluated.
059c696f
KZ
660 *
661 * Returns: a tab entry or NULL.
662 */
68164f6c 663struct libmnt_fs *mnt_table_find_pair(struct libmnt_table *tb, const char *source,
059c696f
KZ
664 const char *target, int direction)
665{
68164f6c
KZ
666 struct libmnt_fs *fs = NULL;
667 struct libmnt_iter itr;
059c696f
KZ
668
669 assert(tb);
670 assert(source);
671 assert(target);
672
673 if (!tb || !source || !target)
674 return NULL;
675
676 DBG(TAB, mnt_debug_h(tb, "lookup SOURCE: %s TARGET: %s", source, target));
677
678 mnt_reset_iter(&itr, direction);
68164f6c 679 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
059c696f
KZ
680
681 if (mnt_fs_match_target(fs, target, tb->cache) &&
682 mnt_fs_match_source(fs, source, tb->cache))
683 return fs;
684 }
685
686 return NULL;
687}
688
6bd8b7a7 689#ifdef TEST_PROGRAM
fbb3eb85 690
68164f6c 691static int parser_errcb(struct libmnt_table *tb, const char *filename, int line)
fbb3eb85
KZ
692{
693 fprintf(stderr, "%s:%d: parse error\n", filename, line);
c3b0d5b3
KZ
694
695 return 1; /* all errors are recoverable -- this is default */
fbb3eb85
KZ
696}
697
68164f6c 698struct libmnt_table *create_table(const char *file)
6bd8b7a7 699{
68164f6c 700 struct libmnt_table *tb;
6bd8b7a7
KZ
701
702 if (!file)
703 return NULL;
68164f6c 704 tb = mnt_new_table();
6bd8b7a7
KZ
705 if (!tb)
706 goto err;
fbb3eb85 707
68164f6c 708 mnt_table_set_parser_errcb(tb, parser_errcb);
fbb3eb85 709
68164f6c 710 if (mnt_table_parse_file(tb, file) != 0)
6bd8b7a7 711 goto err;
6bd8b7a7
KZ
712 return tb;
713err:
c3b0d5b3 714 fprintf(stderr, "%s: parsing failed\n", file);
68164f6c 715 mnt_free_table(tb);
6bd8b7a7
KZ
716 return NULL;
717}
718
68164f6c 719int test_copy_fs(struct libmnt_test *ts, int argc, char *argv[])
6d94f2dc 720{
68164f6c
KZ
721 struct libmnt_table *tb;
722 struct libmnt_fs *fs;
059c696f 723 int rc = -1;
6d94f2dc 724
68164f6c 725 tb = create_table(argv[1]);
6d94f2dc
KZ
726 if (!tb)
727 return -1;
728
68164f6c 729 fs = mnt_table_find_target(tb, "/", MNT_ITER_FORWARD);
6d94f2dc 730 if (!fs)
059c696f 731 goto done;
6d94f2dc
KZ
732
733 printf("ORIGINAL:\n");
734 mnt_fs_print_debug(fs, stdout);
735
736 fs = mnt_copy_fs(fs);
737 if (!fs)
059c696f 738 goto done;
6d94f2dc
KZ
739
740 printf("COPY:\n");
741 mnt_fs_print_debug(fs, stdout);
742 mnt_free_fs(fs);
059c696f
KZ
743 rc = 0;
744done:
68164f6c 745 mnt_free_table(tb);
059c696f 746 return rc;
6d94f2dc
KZ
747}
748
68164f6c 749int test_parse(struct libmnt_test *ts, int argc, char *argv[])
6bd8b7a7 750{
68164f6c
KZ
751 struct libmnt_table *tb = NULL;
752 struct libmnt_iter *itr = NULL;
753 struct libmnt_fs *fs;
059c696f 754 int rc = -1;
6bd8b7a7 755
68164f6c 756 tb = create_table(argv[1]);
6bd8b7a7
KZ
757 if (!tb)
758 return -1;
759
efe73c3e
KZ
760 itr = mnt_new_iter(MNT_ITER_FORWARD);
761 if (!itr)
059c696f 762 goto done;
fbb3eb85 763
68164f6c 764 while(mnt_table_next_fs(tb, itr, &fs) == 0)
efe73c3e 765 mnt_fs_print_debug(fs, stdout);
059c696f
KZ
766 rc = 0;
767done:
efe73c3e 768 mnt_free_iter(itr);
68164f6c 769 mnt_free_table(tb);
059c696f 770 return rc;
6bd8b7a7
KZ
771}
772
68164f6c 773int test_find(struct libmnt_test *ts, int argc, char *argv[], int dr)
6bd8b7a7 774{
68164f6c
KZ
775 struct libmnt_table *tb;
776 struct libmnt_fs *fs = NULL;
777 struct libmnt_cache *mpc = NULL;
6bd8b7a7 778 const char *file, *find, *what;
059c696f 779 int rc = -1;
6bd8b7a7
KZ
780
781 if (argc != 4) {
782 fprintf(stderr, "try --help\n");
059c696f 783 return -EINVAL;
6bd8b7a7
KZ
784 }
785
786 file = argv[1], find = argv[2], what = argv[3];
787
68164f6c 788 tb = create_table(file);
6bd8b7a7 789 if (!tb)
059c696f 790 goto done;
6bd8b7a7
KZ
791
792 /* create a cache for canonicalized paths */
793 mpc = mnt_new_cache();
794 if (!mpc)
059c696f 795 goto done;
68164f6c 796 mnt_table_set_cache(tb, mpc);
6bd8b7a7
KZ
797
798 if (strcasecmp(find, "source") == 0)
68164f6c 799 fs = mnt_table_find_source(tb, what, dr);
6bd8b7a7 800 else if (strcasecmp(find, "target") == 0)
68164f6c 801 fs = mnt_table_find_target(tb, what, dr);
6bd8b7a7
KZ
802
803 if (!fs)
804 fprintf(stderr, "%s: not found %s '%s'\n", file, find, what);
805 else {
5e31c2c8 806 mnt_fs_print_debug(fs, stdout);
059c696f 807 rc = 0;
6bd8b7a7 808 }
059c696f 809done:
68164f6c 810 mnt_free_table(tb);
6bd8b7a7 811 mnt_free_cache(mpc);
059c696f 812 return rc;
6bd8b7a7
KZ
813}
814
68164f6c 815int test_find_bw(struct libmnt_test *ts, int argc, char *argv[])
6bd8b7a7
KZ
816{
817 return test_find(ts, argc, argv, MNT_ITER_BACKWARD);
818}
819
68164f6c 820int test_find_fw(struct libmnt_test *ts, int argc, char *argv[])
6bd8b7a7
KZ
821{
822 return test_find(ts, argc, argv, MNT_ITER_FORWARD);
823}
824
68164f6c 825int test_find_pair(struct libmnt_test *ts, int argc, char *argv[])
059c696f 826{
68164f6c
KZ
827 struct libmnt_table *tb;
828 struct libmnt_fs *fs;
059c696f
KZ
829 int rc = -1;
830
68164f6c 831 tb = create_table(argv[1]);
059c696f
KZ
832 if (!tb)
833 return -1;
834
68164f6c 835 fs = mnt_table_find_pair(tb, argv[2], argv[3], MNT_ITER_FORWARD);
059c696f
KZ
836 if (!fs)
837 goto done;
838
839 mnt_fs_print_debug(fs, stdout);
840 rc = 0;
841done:
68164f6c 842 mnt_free_table(tb);
059c696f
KZ
843 return rc;
844}
845
6bd8b7a7
KZ
846int main(int argc, char *argv[])
847{
68164f6c 848 struct libmnt_test tss[] = {
6bd8b7a7
KZ
849 { "--parse", test_parse, "<file> parse and print tab" },
850 { "--find-forward", test_find_fw, "<file> <source|target> <string>" },
851 { "--find-backward", test_find_bw, "<file> <source|target> <string>" },
059c696f 852 { "--find-pair", test_find_pair, "<file> <source> <target>" },
6d94f2dc 853 { "--copy-fs", test_copy_fs, "<file> copy root FS from the file" },
6bd8b7a7
KZ
854 { NULL }
855 };
856
857 return mnt_run_test(tss, argc, argv);
858}
859
860#endif /* TEST_PROGRAM */