]> git.ipfire.org Git - thirdparty/util-linux.git/blame - shlibs/mount/src/tab.c
libmount: add new psetudo filesystems
[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
3d735589 10 * @title: FS container
192c6aad
KZ
11 * @short_description: container for entries from fstab/mtab/mountinfo
12 *
6bd8b7a7 13 *
192c6aad
KZ
14 * Note that mnt_tab_find_* functions are mount(8) compatible. These functions
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>
192c6aad 28 * mnt_tab_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>
192c6aad 34 * mnt_tab_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>
40 * mnt_tab_find_source(tb, "UUID=anyuuid", &fs);
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/**
61 * mnt_new_tab:
6bd8b7a7
KZ
62 *
63 * The tab is a container for mnt_fs entries that usually represents a fstab,
64 * mtab or mountinfo file from your system.
65 *
9ed7507c 66 * See also mnt_tab_parse_file().
6bd8b7a7 67 *
192c6aad 68 * Returns: newly allocated tab struct.
6bd8b7a7 69 */
9ed7507c 70mnt_tab *mnt_new_tab(void)
6bd8b7a7
KZ
71{
72 mnt_tab *tb = NULL;
73
74 tb = calloc(1, sizeof(struct _mnt_tab));
75 if (!tb)
9ed7507c
KZ
76 return NULL;
77
78 DBG(DEBUG_TAB, fprintf(stderr, "libmount: new tab %p\n", tb));
6bd8b7a7 79
6bd8b7a7
KZ
80 INIT_LIST_HEAD(&tb->ents);
81 return tb;
6bd8b7a7
KZ
82}
83
84/**
85 * mnt_free_tab:
3d735589 86 * @tb: tab pointer
6bd8b7a7
KZ
87 *
88 * Deallocates tab struct and all entries.
89 */
90void mnt_free_tab(mnt_tab *tb)
91{
92 if (!tb)
93 return;
6bd8b7a7
KZ
94
95 while (!list_empty(&tb->ents)) {
96 mnt_fs *fs = list_entry(tb->ents.next, mnt_fs, ents);
97 mnt_free_fs(fs);
98 }
99
100 free(tb);
101}
102
103/**
104 * mnt_tab_get_nents:
105 * @tb: pointer to tab
106 *
192c6aad 107 * Returns: number of valid entries in tab.
6bd8b7a7
KZ
108 */
109int mnt_tab_get_nents(mnt_tab *tb)
110{
111 assert(tb);
112 return tb ? tb->nents : 0;
113}
114
115/**
116 * mnt_tab_set_cache:
117 * @tb: pointer to tab
118 * @mpc: pointer to mnt_cache instance
119 *
120 * Setups a cache for canonicalized paths and evaluated tags (LABEL/UUID). The
121 * cache is recommended for mnt_tab_find_*() functions.
122 *
123 * The cache could be shared between more tabs. Be careful when you share the
124 * same cache between more threads -- currently the cache does not provide any
125 * locking method.
126 *
127 * See also mnt_new_cache().
128 *
59ae0ddd 129 * Returns: 0 on success or negative number in case of error.
6bd8b7a7
KZ
130 */
131int mnt_tab_set_cache(mnt_tab *tb, mnt_cache *mpc)
132{
133 assert(tb);
134 if (!tb)
59ae0ddd 135 return -EINVAL;
6bd8b7a7
KZ
136 tb->cache = mpc;
137 return 0;
138}
139
140/**
141 * mnt_tab_get_cache:
142 * @tb: pointer to tab
143 *
192c6aad 144 * Returns: pointer to mnt_cache instance or NULL.
6bd8b7a7
KZ
145 */
146mnt_cache *mnt_tab_get_cache(mnt_tab *tb)
147{
148 assert(tb);
149 return tb ? tb->cache : NULL;
150}
151
6bd8b7a7
KZ
152/**
153 * mnt_tab_add_fs:
154 * @tb: tab pointer
155 * @fs: new entry
156 *
157 * Adds a new entry to tab.
158 *
59ae0ddd 159 * Returns: 0 on success or negative number in case of error.
6bd8b7a7
KZ
160 */
161int mnt_tab_add_fs(mnt_tab *tb, mnt_fs *fs)
162{
163 assert(tb);
164 assert(fs);
165
166 if (!tb || !fs)
59ae0ddd 167 return -EINVAL;
6bd8b7a7
KZ
168
169 list_add_tail(&fs->ents, &tb->ents);
170
171 DBG(DEBUG_TAB, fprintf(stderr,
9ed7507c
KZ
172 "libmount: tab %p: add entry: %s %s\n",
173 tb, mnt_fs_get_source(fs),
6bd8b7a7
KZ
174 mnt_fs_get_target(fs)));
175
911238af 176 tb->nents++;
6bd8b7a7
KZ
177 return 0;
178}
179
180/**
181 * mnt_tab_remove_fs:
182 * @tb: tab pointer
183 * @fs: new entry
184 *
59ae0ddd 185 * Returns: 0 on success or negative number in case of error.
6bd8b7a7
KZ
186 */
187int mnt_tab_remove_fs(mnt_tab *tb, mnt_fs *fs)
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
KZ
199/**
200 * mnt_tab_get_root_fs:
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 */
206int mnt_tab_get_root_fs(mnt_tab *tb, mnt_fs **root)
207{
208 mnt_iter itr;
209 mnt_fs *fs;
210 int root_id = 0;
211
212 assert(tb);
213 assert(root);
214
215 if (!tb || !root)
59ae0ddd 216 return -EINVAL;
26b4f9e4 217
9ed7507c 218 DBG(DEBUG_TAB, fprintf(stderr, "libmount: tab %p: lookup root fs\n", tb));
20aae9d3 219
26b4f9e4
KZ
220 mnt_reset_iter(&itr, MNT_ITER_FORWARD);
221 while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
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/**
236 * mnt_tab_next_child_fs:
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
KZ
246 */
247int mnt_tab_next_child_fs(mnt_tab *tb, mnt_iter *itr,
248 mnt_fs *parent, mnt_fs **chld)
249{
250 mnt_fs *fs;
251 int parent_id, lastchld_id = 0, chld_id = 0;
252
253 if (!tb || !itr || !parent)
59ae0ddd 254 return -EINVAL;
26b4f9e4 255
20aae9d3 256 DBG(DEBUG_TAB, fprintf(stderr,
9ed7507c
KZ
257 "libmount: tab %p: lookup next child of %s\n",
258 tb, mnt_fs_get_target(parent)));
20aae9d3 259
26b4f9e4
KZ
260 parent_id = mnt_fs_get_id(parent);
261 if (!parent_id)
59ae0ddd 262 return -EINVAL;
26b4f9e4
KZ
263
264 /* get ID of the previously returned child */
265 if (itr->head && itr->p != itr->head) {
266 MNT_ITER_ITERATE(itr, fs, struct _mnt_fs, ents);
267 lastchld_id = mnt_fs_get_id(fs);
268 }
269
270 *chld = NULL;
271
272 mnt_reset_iter(itr, MNT_ITER_FORWARD);
273 while(mnt_tab_next_fs(tb, itr, &fs) == 0) {
274 int id;
275
276 if (mnt_fs_get_parent_id(fs) != parent_id)
277 continue;
278
279 id = mnt_fs_get_id(fs);
280
281 if ((!lastchld_id || id > lastchld_id) &&
282 (!*chld || id < chld_id)) {
283 *chld = fs;
284 chld_id = id;
285 }
286 }
287
288 if (!chld_id)
289 return 1; /* end of iterator */
290
291 /* set the iterator to the @chld for the next call */
292 mnt_tab_set_iter(tb, itr, *chld);
293
294 return 0;
295}
296
6bd8b7a7
KZ
297/**
298 * mnt_tab_next_fs:
299 * @tb: tab pointer
300 * @itr: iterator
301 * @fs: returns the next tab entry
302 *
59ae0ddd 303 * Returns: 0 on success, negative number in case of error or 1 at end of list.
6bd8b7a7
KZ
304 *
305 * Example (list all mountpoints from fstab in backward order):
3d735589
KZ
306 * <informalexample>
307 * <programlisting>
6bd8b7a7
KZ
308 * mnt_fs *fs;
309 * mnt_tab *tb = mnt_new_tab("/etc/fstab");
310 * mnt_iter *itr = mnt_new_iter(MNT_ITER_BACKWARD);
311 *
312 * mnt_tab_parse_file(tb);
313 *
314 * while(mnt_tab_next_fs(tb, itr, &fs) == 0) {
315 * const char *dir = mnt_fs_get_target(fs);
316 * printf("mount point: %s\n", dir);
317 * }
318 * mnt_free_tab(fi);
3d735589
KZ
319 * </programlisting>
320 * </informalexample>
6bd8b7a7
KZ
321 */
322int mnt_tab_next_fs(mnt_tab *tb, mnt_iter *itr, mnt_fs **fs)
323{
59ae0ddd 324 int rc = 1;
3fca8422 325
6bd8b7a7
KZ
326 assert(tb);
327 assert(itr);
328 assert(fs);
329
330 if (!tb || !itr || !fs)
59ae0ddd 331 return -EINVAL;
0532ba1d
KZ
332 *fs = NULL;
333
6bd8b7a7
KZ
334 if (!itr->head)
335 MNT_ITER_INIT(itr, &tb->ents);
336 if (itr->p != itr->head) {
337 MNT_ITER_ITERATE(itr, *fs, struct _mnt_fs, ents);
3fca8422 338 rc = 0;
6bd8b7a7
KZ
339 }
340
3fca8422
KZ
341 return rc;
342}
343
344/**
345 * mnt_tab_find_next_fs:
346 * @tb: table
347 * @itr: iterator
348 * @match_func: function returns 1 or 0
3d735589 349 * @userdata: extra data for match_func
3fca8422
KZ
350 * @fs: returns pointer to the next matching table entry
351 *
352 * This function allows search in @tb.
353 *
59ae0ddd 354 * Returns: negative number in case of error, 1 at end of table or 0 o success.
3fca8422
KZ
355 */
356int mnt_tab_find_next_fs(mnt_tab *tb, mnt_iter *itr,
357 int (*match_func)(mnt_fs *, void *), void *userdata,
358 mnt_fs **fs)
359{
360 if (!tb || !itr || !fs || !match_func)
59ae0ddd 361 return -EINVAL;
3fca8422 362
20aae9d3 363 DBG(DEBUG_TAB, fprintf(stderr,
9ed7507c 364 "libmount: tab %p: lookup next fs\n", tb));
20aae9d3 365
3fca8422
KZ
366 if (!itr->head)
367 MNT_ITER_INIT(itr, &tb->ents);
368
369 do {
370 if (itr->p != itr->head)
371 MNT_ITER_ITERATE(itr, *fs, struct _mnt_fs, ents);
372 else
373 break; /* end */
374
3fca8422
KZ
375 if (match_func(*fs, userdata))
376 return 0;
377 } while(1);
378
26b4f9e4 379 *fs = NULL;
6bd8b7a7
KZ
380 return 1;
381}
382
383/**
384 * mnt_tab_set_iter:
385 * @tb: tab pointer
386 * @itr: iterator
387 * @fs: tab entry
388 *
389 * Sets @iter to the position of @fs in the file @tb.
390 *
59ae0ddd 391 * Returns: 0 on success, negative number in case of error.
6bd8b7a7
KZ
392 */
393int mnt_tab_set_iter(mnt_tab *tb, mnt_iter *itr, mnt_fs *fs)
394{
395 assert(tb);
396 assert(itr);
397 assert(fs);
398
399 if (!tb || !itr || !fs)
59ae0ddd 400 return -EINVAL;
6bd8b7a7
KZ
401
402 MNT_ITER_INIT(itr, &tb->ents);
403 itr->p = &fs->ents;
404
405 return 0;
406}
407
408/**
409 * mnt_tab_find_target:
410 * @tb: tab pointer
411 * @path: mountpoint directory
412 * @direction: MNT_ITER_{FORWARD,BACKWARD}
413 *
414 * Try to lookup an entry in given tab, possible are three iterations, first
415 * with @path, second with realpath(@path) and third with realpath(@path)
416 * against realpath(fs->target). The 2nd and 3rd iterations are not performed
417 * when @tb cache is not set (see mnt_tab_set_cache()).
418 *
192c6aad 419 * Returns: a tab entry or NULL.
6bd8b7a7
KZ
420 */
421mnt_fs *mnt_tab_find_target(mnt_tab *tb, const char *path, int direction)
422{
423 mnt_iter itr;
424 mnt_fs *fs = NULL;
425 char *cn;
426
427 assert(tb);
428 assert(path);
429
59ae0ddd
KZ
430 if (!tb || !path)
431 return NULL;
432
6bd8b7a7 433 DBG(DEBUG_TAB, fprintf(stderr,
9ed7507c 434 "libmount: tab %p: lookup target: %s\n", tb, path));
6bd8b7a7
KZ
435
436 /* native @target */
437 mnt_reset_iter(&itr, direction);
438 while(mnt_tab_next_fs(tb, &itr, &fs) == 0)
439 if (fs->target && strcmp(fs->target, path) == 0)
440 return fs;
441
442 if (!tb->cache || !(cn = mnt_resolve_path(path, tb->cache)))
443 return NULL;
444
445 /* canonicalized paths in mnt_tab */
446 mnt_reset_iter(&itr, direction);
447 while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
448 if (fs->target && strcmp(fs->target, cn) == 0)
449 return fs;
450 }
451
452 /* non-canonicaled path in mnt_tab */
453 mnt_reset_iter(&itr, direction);
454 while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
455 char *p;
456 if (!fs->target)
457 continue;
458 p = mnt_resolve_path(fs->target, tb->cache);
459 if (strcmp(cn, p) == 0)
460 return fs;
461 }
462 return NULL;
463}
464
465/**
466 * mnt_tab_find_srcpath:
467 * @tb: tab pointer
468 * @path: source path (devname or dirname)
469 * @direction: MNT_ITER_{FORWARD,BACKWARD}
470 *
471 * Try to lookup an entry in given tab, possible are four iterations, first
472 * with @path, second with realpath(@path), third with tags (LABEL, UUID, ..)
473 * from @path and fourth with realpath(@path) against realpath(entry->srcpath).
474 *
475 * The 2nd, 3rd and 4th iterations are not performed when @tb cache is not
476 * set (see mnt_tab_set_cache()).
477 *
192c6aad 478 * Returns: a tab entry or NULL.
6bd8b7a7
KZ
479 */
480mnt_fs *mnt_tab_find_srcpath(mnt_tab *tb, const char *path, int direction)
481{
482 mnt_iter itr;
483 mnt_fs *fs = NULL;
484 int ntags = 0;
485 char *cn;
486 const char *p;
487
488 assert(tb);
489 assert(path);
490
491 DBG(DEBUG_TAB, fprintf(stderr,
9ed7507c 492 "libmount: tab %p: lookup srcpath: %s\n", tb, path));
6bd8b7a7
KZ
493
494 /* native paths */
495 mnt_reset_iter(&itr, direction);
496 while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
497 p = mnt_fs_get_srcpath(fs);
498 if (p && strcmp(p, path) == 0)
499 return fs;
500 if (!p)
501 /* mnt_fs_get_srcpath() returs nothing, it's TAG */
502 ntags++;
503 }
504
505 if (!tb->cache || !(cn = mnt_resolve_path(path, tb->cache)))
506 return NULL;
507
508 /* canonicalized paths in mnt_tab */
509 if (ntags < mnt_tab_get_nents(tb)) {
510 mnt_reset_iter(&itr, direction);
511 while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
512 p = mnt_fs_get_srcpath(fs);
513 if (p && strcmp(p, cn) == 0)
514 return fs;
515 }
516 }
517
518 /* evaluated tag */
3fca8422 519 if (ntags) {
ba7232a1
KZ
520 int rc = mnt_cache_read_tags(tb->cache, cn);
521
6bd8b7a7 522 mnt_reset_iter(&itr, direction);
6bd8b7a7 523
ba7232a1 524 if (rc == 0) {
3fca8422
KZ
525 /* @path's TAGs are in the cache */
526 while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
527 const char *t, *v;
6bd8b7a7 528
3fca8422
KZ
529 if (mnt_fs_get_tag(fs, &t, &v))
530 continue;
531
532 if (mnt_cache_device_has_tag(tb->cache, cn, t, v))
533 return fs;
534 }
ba7232a1 535 } else if (rc < 0 && errno == EACCES) {
3fca8422
KZ
536 /* @path is unaccessible, try evaluate all TAGs in @tb
537 * by udev symlinks -- this could be expensive on systems
538 * with huge fstab/mtab */
539 while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
540 const char *t, *v, *x;
541 if (mnt_fs_get_tag(fs, &t, &v))
542 continue;
543 x = mnt_resolve_tag(t, v, tb->cache);
544 if (x && !strcmp(x, cn))
545 return fs;
546 }
6bd8b7a7
KZ
547 }
548 }
549
550 /* non-canonicalized paths in mnt_tab */
551 if (ntags <= mnt_tab_get_nents(tb)) {
552 mnt_reset_iter(&itr, direction);
553 while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
554 p = mnt_fs_get_srcpath(fs);
555 if (p)
556 p = mnt_resolve_path(p, tb->cache);
557 if (p && strcmp(cn, p) == 0)
558 return fs;
559 }
560 }
561
562 return NULL;
563}
564
565
566/**
567 * mnt_tab_find_tag:
568 * @tb: tab pointer
569 * @tag: tag name (e.g "LABEL", "UUID", ...)
570 * @val: tag value
571 * @direction: MNT_ITER_{FORWARD,BACKWARD}
572 *
573 * Try to lookup an entry in given tab, first attempt is lookup by @tag and
574 * @val, for the second attempt the tag is evaluated (converted to the device
575 * name) and mnt_tab_find_srcpath() is preformed. The second attempt is not
576 * performed when @tb cache is not set (see mnt_tab_set_cache()).
577
192c6aad 578 * Returns: a tab entry or NULL.
6bd8b7a7
KZ
579 */
580mnt_fs *mnt_tab_find_tag(mnt_tab *tb, const char *tag,
581 const char *val, int direction)
582{
583 mnt_iter itr;
584 mnt_fs *fs = NULL;
585
586 assert(tb);
587 assert(tag);
588 assert(val);
589
590 if (!tb || !tag || !val)
591 return NULL;
592
593 DBG(DEBUG_TAB, fprintf(stderr,
9ed7507c 594 "libmount: tab %p: lookup by TAG: %s %s\n", tb, tag, val));
6bd8b7a7
KZ
595
596 /* look up by TAG */
597 mnt_reset_iter(&itr, direction);
598 while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
599 if (fs->tagname && fs->tagval &&
600 strcmp(fs->tagname, tag) == 0 &&
601 strcmp(fs->tagval, val) == 0)
602 return fs;
603 }
604
605 if (tb->cache) {
606 /* look up by device name */
607 char *cn = mnt_resolve_tag(tag, val, tb->cache);
608 if (cn)
609 return mnt_tab_find_srcpath(tb, cn, direction);
610 }
611 return NULL;
612}
613
614/**
615 * mnt_tab_find_source:
616 * @tb: tab pointer
617 * @source: TAG or path
3d735589 618 * @direction: MNT_ITER_{FORWARD,BACKWARD}
6bd8b7a7
KZ
619 *
620 * This is high-level API for mnt_tab_find_{srcpath,tag}. You needn't to care
621 * about @source format (device, LABEL, UUID, ...). This function parses @source
622 * and calls mnt_tab_find_tag() or mnt_tab_find_srcpath().
623 *
192c6aad 624 * Returns: a tab entry or NULL.
6bd8b7a7
KZ
625 */
626mnt_fs *mnt_tab_find_source(mnt_tab *tb, const char *source, int direction)
627{
628 mnt_fs *fs = NULL;
629
630 assert(tb);
631 assert(source);
632
633 if (!tb || !source)
634 return NULL;
635
636 DBG(DEBUG_TAB, fprintf(stderr,
9ed7507c 637 "libmount: tab %p: lookup SOURCE: %s\n", tb, source));
6bd8b7a7
KZ
638
639 if (strchr(source, '=')) {
640 char *tag, *val;
641
642 if (blkid_parse_tag_string(source, &tag, &val) == 0) {
643
644 fs = mnt_tab_find_tag(tb, tag, val, direction);
645
646 free(tag);
647 free(val);
648 }
649 } else
650 fs = mnt_tab_find_srcpath(tb, source, direction);
651
652 return fs;
653}
654
6bd8b7a7 655#ifdef TEST_PROGRAM
fbb3eb85
KZ
656
657static int parser_errcb(mnt_tab *tb, const char *filename, int line, int flag)
658{
659 fprintf(stderr, "%s:%d: parse error\n", filename, line);
660 return 0;
661}
662
6bd8b7a7
KZ
663mnt_tab *create_tab(const char *file)
664{
665 mnt_tab *tb;
666
667 if (!file)
668 return NULL;
9ed7507c 669 tb = mnt_new_tab();
6bd8b7a7
KZ
670 if (!tb)
671 goto err;
fbb3eb85
KZ
672
673 mnt_tab_set_parser_errcb(tb, parser_errcb);
674
9ed7507c 675 if (mnt_tab_parse_file(tb, file) != 0)
6bd8b7a7 676 goto err;
6bd8b7a7
KZ
677 return tb;
678err:
679 mnt_free_tab(tb);
680 return NULL;
681}
682
6d94f2dc
KZ
683int test_copy_fs(struct mtest *ts, int argc, char *argv[])
684{
685 mnt_tab *tb;
686 mnt_fs *fs;
687
688 tb = create_tab(argv[1]);
689 if (!tb)
690 return -1;
691
692 fs = mnt_tab_find_target(tb, "/", MNT_ITER_FORWARD);
693 if (!fs)
694 goto err;
695
696 printf("ORIGINAL:\n");
697 mnt_fs_print_debug(fs, stdout);
698
699 fs = mnt_copy_fs(fs);
700 if (!fs)
701 goto err;
702
703 printf("COPY:\n");
704 mnt_fs_print_debug(fs, stdout);
705 mnt_free_fs(fs);
706err:
707 mnt_free_tab(tb);
708 return 0;
709}
710
6bd8b7a7
KZ
711int test_parse(struct mtest *ts, int argc, char *argv[])
712{
713 mnt_tab *tb;
efe73c3e
KZ
714 mnt_iter *itr;
715 mnt_fs *fs;
6bd8b7a7
KZ
716
717 tb = create_tab(argv[1]);
718 if (!tb)
719 return -1;
720
efe73c3e
KZ
721 itr = mnt_new_iter(MNT_ITER_FORWARD);
722 if (!itr)
723 goto err;
fbb3eb85 724
efe73c3e
KZ
725 while(mnt_tab_next_fs(tb, itr, &fs) == 0)
726 mnt_fs_print_debug(fs, stdout);
727err:
728 mnt_free_iter(itr);
6bd8b7a7
KZ
729 mnt_free_tab(tb);
730 return 0;
731}
732
733int test_find(struct mtest *ts, int argc, char *argv[], int dr)
734{
735 mnt_tab *tb;
736 mnt_fs *fs = NULL;
737 mnt_cache *mpc;
738 const char *file, *find, *what;
739
740 if (argc != 4) {
741 fprintf(stderr, "try --help\n");
742 goto err;
743 }
744
745 file = argv[1], find = argv[2], what = argv[3];
746
747 tb = create_tab(file);
748 if (!tb)
749 goto err;
750
751 /* create a cache for canonicalized paths */
752 mpc = mnt_new_cache();
753 if (!mpc)
754 goto err;
755 mnt_tab_set_cache(tb, mpc);
756
757 if (strcasecmp(find, "source") == 0)
758 fs = mnt_tab_find_source(tb, what, dr);
759 else if (strcasecmp(find, "target") == 0)
760 fs = mnt_tab_find_target(tb, what, dr);
761
762 if (!fs)
763 fprintf(stderr, "%s: not found %s '%s'\n", file, find, what);
764 else {
765 const char *s = mnt_fs_get_srcpath(fs);
766 if (s)
767 printf("%s", s);
768 else {
769 const char *tag, *val;
770 mnt_fs_get_tag(fs, &tag, &val);
771 printf("%s=%s", tag, val);
772 }
773 printf("|%s|%s\n", mnt_fs_get_target(fs),
774 mnt_fs_get_optstr(fs));
775 }
776 mnt_free_tab(tb);
777 mnt_free_cache(mpc);
778 return 0;
779err:
780 return -1;
781}
782
783int test_find_bw(struct mtest *ts, int argc, char *argv[])
784{
785 return test_find(ts, argc, argv, MNT_ITER_BACKWARD);
786}
787
788int test_find_fw(struct mtest *ts, int argc, char *argv[])
789{
790 return test_find(ts, argc, argv, MNT_ITER_FORWARD);
791}
792
793int main(int argc, char *argv[])
794{
795 struct mtest tss[] = {
6bd8b7a7
KZ
796 { "--parse", test_parse, "<file> parse and print tab" },
797 { "--find-forward", test_find_fw, "<file> <source|target> <string>" },
798 { "--find-backward", test_find_bw, "<file> <source|target> <string>" },
6d94f2dc 799 { "--copy-fs", test_copy_fs, "<file> copy root FS from the file" },
6bd8b7a7
KZ
800 { NULL }
801 };
802
803 return mnt_run_test(tss, argc, argv);
804}
805
806#endif /* TEST_PROGRAM */