]> git.ipfire.org Git - thirdparty/util-linux.git/blame - shlibs/mount/src/tab.c
libmount: add support for userdata and work with VFS tree
[thirdparty/util-linux.git] / shlibs / mount / src / tab.c
CommitLineData
6bd8b7a7
KZ
1/*
2 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
3 *
4 * This file may be redistributed under the terms of the
5 * GNU Lesser General Public License.
6 *
7 * Note:
8 * mnt_tab_find_* functions are mount(8) compatible. It means it tries
9 * to found an entry in more iterations where the first attempt is always
10 * based on comparison with unmodified (non-canonicalized or un-evaluated)
11 * paths or tags. For example fstab with two entries:
12 *
13 * LABEL=foo /foo auto rw
14 * /dev/foo /foo auto rw
15 *
16 * where both lines are used for the *same* device, then
17 *
18 * mnt_tab_find_source(tb, "/dev/foo", &fs);
19 *
20 * will returns the second line, and
21 *
22 * mnt_tab_find_source(tb, "LABEL=foo", &fs);
23 *
24 * will returns the first entry, and
25 *
26 * mnt_tab_find_source(tb, "UUID=<anyuuid>", &fs);
27 *
28 * will returns the first entry (if UUID matches with the device).
29 */
30
31#include <string.h>
32#include <stdlib.h>
33#include <ctype.h>
3fca8422 34#include <errno.h>
6bd8b7a7
KZ
35#include <limits.h>
36#include <sys/types.h>
37#include <sys/stat.h>
38#include <unistd.h>
39#include <blkid/blkid.h>
40
41#include "nls.h"
42#include "mountP.h"
43
44/**
45 * mnt_new_tab:
46 * @filename: file name or NULL
47 *
48 * The tab is a container for mnt_fs entries that usually represents a fstab,
49 * mtab or mountinfo file from your system.
50 *
51 * Note that this function does not parse the file. See also
52 * mnt_tab_parse_file().
53 *
54 * Returns newly allocated tab struct.
55 */
56mnt_tab *mnt_new_tab(const char *filename)
57{
58 mnt_tab *tb = NULL;
59
60 tb = calloc(1, sizeof(struct _mnt_tab));
61 if (!tb)
62 goto err;
63
64 if (filename) {
65 tb->filename = strdup(filename);
66 if (!tb->filename)
67 goto err;
68 }
69 INIT_LIST_HEAD(&tb->ents);
70 return tb;
71err:
72 free(tb);
73 return NULL;
74}
75
76/**
77 * mnt_free_tab:
78 * @tab: tab pointer
79 *
80 * Deallocates tab struct and all entries.
81 */
82void mnt_free_tab(mnt_tab *tb)
83{
84 if (!tb)
85 return;
86 free(tb->filename);
87
88 while (!list_empty(&tb->ents)) {
89 mnt_fs *fs = list_entry(tb->ents.next, mnt_fs, ents);
90 mnt_free_fs(fs);
91 }
92
93 free(tb);
94}
95
96/**
97 * mnt_tab_get_nents:
98 * @tb: pointer to tab
99 *
100 * Returns number of valid entries in tab.
101 */
102int mnt_tab_get_nents(mnt_tab *tb)
103{
104 assert(tb);
105 return tb ? tb->nents : 0;
106}
107
108/**
109 * mnt_tab_set_cache:
110 * @tb: pointer to tab
111 * @mpc: pointer to mnt_cache instance
112 *
113 * Setups a cache for canonicalized paths and evaluated tags (LABEL/UUID). The
114 * cache is recommended for mnt_tab_find_*() functions.
115 *
116 * The cache could be shared between more tabs. Be careful when you share the
117 * same cache between more threads -- currently the cache does not provide any
118 * locking method.
119 *
120 * See also mnt_new_cache().
121 *
122 * Returns 0 on success or -1 in case of error.
123 */
124int mnt_tab_set_cache(mnt_tab *tb, mnt_cache *mpc)
125{
126 assert(tb);
127 if (!tb)
128 return -1;
129 tb->cache = mpc;
130 return 0;
131}
132
133/**
134 * mnt_tab_get_cache:
135 * @tb: pointer to tab
136 *
137 * Returns pointer to mnt_cache instance or NULL.
138 */
139mnt_cache *mnt_tab_get_cache(mnt_tab *tb)
140{
141 assert(tb);
142 return tb ? tb->cache : NULL;
143}
144
145/**
146 * mnt_tab_get_name:
147 * @tb: tab pointer
148 *
149 * Returns tab filename or NULL.
150 */
151const char *mnt_tab_get_name(mnt_tab *tb)
152{
153 assert(tb);
154 return tb ? tb->filename : NULL;
155}
156
157/**
158 * mnt_tab_add_fs:
159 * @tb: tab pointer
160 * @fs: new entry
161 *
162 * Adds a new entry to tab.
163 *
164 * Returns 0 on success or -1 in case of error.
165 */
166int mnt_tab_add_fs(mnt_tab *tb, mnt_fs *fs)
167{
168 assert(tb);
169 assert(fs);
170
171 if (!tb || !fs)
172 return -1;
173
174 list_add_tail(&fs->ents, &tb->ents);
175
176 DBG(DEBUG_TAB, fprintf(stderr,
177 "libmount: %s: add entry: %s %s\n",
178 tb->filename, mnt_fs_get_source(fs),
179 mnt_fs_get_target(fs)));
180
181 if (fs->flags & MNT_FS_ERROR)
182 tb->nerrs++;
183 else
184 tb->nents++;
185 return 0;
186}
187
188/**
189 * mnt_tab_remove_fs:
190 * @tb: tab pointer
191 * @fs: new entry
192 *
193 * Returns 0 on success or -1 in case of error.
194 */
195int mnt_tab_remove_fs(mnt_tab *tb, mnt_fs *fs)
196{
197 assert(tb);
198 assert(fs);
199
200 if (!tb || !fs)
201 return -1;
202
203 list_del(&fs->ents);
204
205 if (fs->flags & MNT_FS_ERROR)
206 tb->nerrs--;
207 else
208 tb->nents--;
209 return 0;
210}
211
26b4f9e4
KZ
212/**
213 * mnt_tab_get_root_fs:
214 * @tb: mountinfo file (/proc/self/mountinfo)
215 * @root: returns pointer to the root filesystem (/)
216 *
217 * Returns: 0 on success or -1 case of error.
218 */
219int mnt_tab_get_root_fs(mnt_tab *tb, mnt_fs **root)
220{
221 mnt_iter itr;
222 mnt_fs *fs;
223 int root_id = 0;
224
225 assert(tb);
226 assert(root);
227
228 if (!tb || !root)
229 return -1;
230
231 mnt_reset_iter(&itr, MNT_ITER_FORWARD);
232 while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
233 int id = mnt_fs_get_parent_id(fs);
234 if (!id)
235 break; /* @tab is not mountinfo file? */
236
237 if (!*root || id < root_id) {
238 *root = fs;
239 root_id = id;
240 }
241 }
242
243 return root_id ? 0 : -1;
244}
245
246/**
247 * mnt_tab_next_child_fs:
248 * @tb: mountinfo file (/proc/self/mountinfo)
249 * @parent: parental FS
250 * @chld: returns the next child filesystem
251 *
252 * Note that filesystems are returned in the order how was mounted (according to
253 * IDs in /proc/self/mountinfo).
254 *
255 * Returns 0 on success, -1 in case of error or 1 at end of list.
256 */
257int mnt_tab_next_child_fs(mnt_tab *tb, mnt_iter *itr,
258 mnt_fs *parent, mnt_fs **chld)
259{
260 mnt_fs *fs;
261 int parent_id, lastchld_id = 0, chld_id = 0;
262
263 if (!tb || !itr || !parent)
264 return -1;
265
266 parent_id = mnt_fs_get_id(parent);
267 if (!parent_id)
268 return -1;
269
270 /* get ID of the previously returned child */
271 if (itr->head && itr->p != itr->head) {
272 MNT_ITER_ITERATE(itr, fs, struct _mnt_fs, ents);
273 lastchld_id = mnt_fs_get_id(fs);
274 }
275
276 *chld = NULL;
277
278 mnt_reset_iter(itr, MNT_ITER_FORWARD);
279 while(mnt_tab_next_fs(tb, itr, &fs) == 0) {
280 int id;
281
282 if (mnt_fs_get_parent_id(fs) != parent_id)
283 continue;
284
285 id = mnt_fs_get_id(fs);
286
287 if ((!lastchld_id || id > lastchld_id) &&
288 (!*chld || id < chld_id)) {
289 *chld = fs;
290 chld_id = id;
291 }
292 }
293
294 if (!chld_id)
295 return 1; /* end of iterator */
296
297 /* set the iterator to the @chld for the next call */
298 mnt_tab_set_iter(tb, itr, *chld);
299
300 return 0;
301}
302
6bd8b7a7
KZ
303/**
304 * mnt_tab_next_fs:
305 * @tb: tab pointer
306 * @itr: iterator
307 * @fs: returns the next tab entry
308 *
309 * Returns 0 on success, -1 in case of error or 1 at end of list.
310 *
311 * Example (list all mountpoints from fstab in backward order):
312 *
313 * mnt_fs *fs;
314 * mnt_tab *tb = mnt_new_tab("/etc/fstab");
315 * mnt_iter *itr = mnt_new_iter(MNT_ITER_BACKWARD);
316 *
317 * mnt_tab_parse_file(tb);
318 *
319 * while(mnt_tab_next_fs(tb, itr, &fs) == 0) {
320 * const char *dir = mnt_fs_get_target(fs);
321 * printf("mount point: %s\n", dir);
322 * }
323 * mnt_free_tab(fi);
324 */
325int mnt_tab_next_fs(mnt_tab *tb, mnt_iter *itr, mnt_fs **fs)
326{
3fca8422
KZ
327 int rc;
328
6bd8b7a7
KZ
329 assert(tb);
330 assert(itr);
331 assert(fs);
332
333 if (!tb || !itr || !fs)
334 return -1;
335again:
3fca8422 336 rc = 1;
6bd8b7a7
KZ
337 if (!itr->head)
338 MNT_ITER_INIT(itr, &tb->ents);
339 if (itr->p != itr->head) {
340 MNT_ITER_ITERATE(itr, *fs, struct _mnt_fs, ents);
3fca8422 341 rc = 0;
6bd8b7a7
KZ
342 }
343
344 /* ignore broken entries */
345 if (*fs && ((*fs)->flags & MNT_FS_ERROR))
346 goto again;
347
3fca8422
KZ
348 return rc;
349}
350
351/**
352 * mnt_tab_find_next_fs:
353 * @tb: table
354 * @itr: iterator
355 * @match_func: function returns 1 or 0
356 * @fs: returns pointer to the next matching table entry
357 *
358 * This function allows search in @tb.
359 *
360 * Returns -1 in case of error, 1 at end of table or 0 o success.
361 */
362int mnt_tab_find_next_fs(mnt_tab *tb, mnt_iter *itr,
363 int (*match_func)(mnt_fs *, void *), void *userdata,
364 mnt_fs **fs)
365{
366 if (!tb || !itr || !fs || !match_func)
367 return -1;
368
369 if (!itr->head)
370 MNT_ITER_INIT(itr, &tb->ents);
371
372 do {
373 if (itr->p != itr->head)
374 MNT_ITER_ITERATE(itr, *fs, struct _mnt_fs, ents);
375 else
376 break; /* end */
377
378 if ((*fs)->flags & MNT_FS_ERROR)
379 continue;
380 if (match_func(*fs, userdata))
381 return 0;
382 } while(1);
383
26b4f9e4 384 *fs = NULL;
6bd8b7a7
KZ
385 return 1;
386}
387
388/**
389 * mnt_tab_set_iter:
390 * @tb: tab pointer
391 * @itr: iterator
392 * @fs: tab entry
393 *
394 * Sets @iter to the position of @fs in the file @tb.
395 *
396 * Returns 0 on success, -1 in case of error.
397 */
398int mnt_tab_set_iter(mnt_tab *tb, mnt_iter *itr, mnt_fs *fs)
399{
400 assert(tb);
401 assert(itr);
402 assert(fs);
403
404 if (!tb || !itr || !fs)
405 return -1;
406
407 MNT_ITER_INIT(itr, &tb->ents);
408 itr->p = &fs->ents;
409
410 return 0;
411}
412
413/**
414 * mnt_tab_find_target:
415 * @tb: tab pointer
416 * @path: mountpoint directory
417 * @direction: MNT_ITER_{FORWARD,BACKWARD}
418 *
419 * Try to lookup an entry in given tab, possible are three iterations, first
420 * with @path, second with realpath(@path) and third with realpath(@path)
421 * against realpath(fs->target). The 2nd and 3rd iterations are not performed
422 * when @tb cache is not set (see mnt_tab_set_cache()).
423 *
424 * Returns a tab entry or NULL.
425 */
426mnt_fs *mnt_tab_find_target(mnt_tab *tb, const char *path, int direction)
427{
428 mnt_iter itr;
429 mnt_fs *fs = NULL;
430 char *cn;
431
432 assert(tb);
433 assert(path);
434
435 DBG(DEBUG_TAB, fprintf(stderr,
436 "libmount: %s: lookup target: %s\n", tb->filename, path));
437
438 /* native @target */
439 mnt_reset_iter(&itr, direction);
440 while(mnt_tab_next_fs(tb, &itr, &fs) == 0)
441 if (fs->target && strcmp(fs->target, path) == 0)
442 return fs;
443
444 if (!tb->cache || !(cn = mnt_resolve_path(path, tb->cache)))
445 return NULL;
446
447 /* canonicalized paths in mnt_tab */
448 mnt_reset_iter(&itr, direction);
449 while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
450 if (fs->target && strcmp(fs->target, cn) == 0)
451 return fs;
452 }
453
454 /* non-canonicaled path in mnt_tab */
455 mnt_reset_iter(&itr, direction);
456 while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
457 char *p;
458 if (!fs->target)
459 continue;
460 p = mnt_resolve_path(fs->target, tb->cache);
461 if (strcmp(cn, p) == 0)
462 return fs;
463 }
464 return NULL;
465}
466
467/**
468 * mnt_tab_find_srcpath:
469 * @tb: tab pointer
470 * @path: source path (devname or dirname)
471 * @direction: MNT_ITER_{FORWARD,BACKWARD}
472 *
473 * Try to lookup an entry in given tab, possible are four iterations, first
474 * with @path, second with realpath(@path), third with tags (LABEL, UUID, ..)
475 * from @path and fourth with realpath(@path) against realpath(entry->srcpath).
476 *
477 * The 2nd, 3rd and 4th iterations are not performed when @tb cache is not
478 * set (see mnt_tab_set_cache()).
479 *
480 * Returns a tab entry or NULL.
481 */
482mnt_fs *mnt_tab_find_srcpath(mnt_tab *tb, const char *path, int direction)
483{
484 mnt_iter itr;
485 mnt_fs *fs = NULL;
486 int ntags = 0;
487 char *cn;
488 const char *p;
489
490 assert(tb);
491 assert(path);
492
493 DBG(DEBUG_TAB, fprintf(stderr,
494 "libmount: %s: lookup srcpath: %s\n", tb->filename, path));
495
496 /* native paths */
497 mnt_reset_iter(&itr, direction);
498 while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
499 p = mnt_fs_get_srcpath(fs);
500 if (p && strcmp(p, path) == 0)
501 return fs;
502 if (!p)
503 /* mnt_fs_get_srcpath() returs nothing, it's TAG */
504 ntags++;
505 }
506
507 if (!tb->cache || !(cn = mnt_resolve_path(path, tb->cache)))
508 return NULL;
509
510 /* canonicalized paths in mnt_tab */
511 if (ntags < mnt_tab_get_nents(tb)) {
512 mnt_reset_iter(&itr, direction);
513 while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
514 p = mnt_fs_get_srcpath(fs);
515 if (p && strcmp(p, cn) == 0)
516 return fs;
517 }
518 }
519
520 /* evaluated tag */
3fca8422 521 if (ntags) {
6bd8b7a7 522 mnt_reset_iter(&itr, direction);
6bd8b7a7 523
3fca8422
KZ
524 if (mnt_cache_read_tags(tb->cache, cn) > 0) {
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 }
535 } else if (errno == EACCES) {
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
578 * Returns a tab entry or NULL.
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,
594 "libmount: %s: lookup by TAG: %s %s\n", tb->filename, tag, val));
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
618 *
619 * This is high-level API for mnt_tab_find_{srcpath,tag}. You needn't to care
620 * about @source format (device, LABEL, UUID, ...). This function parses @source
621 * and calls mnt_tab_find_tag() or mnt_tab_find_srcpath().
622 *
623 * Returns a tab entry or NULL.
624 */
625mnt_fs *mnt_tab_find_source(mnt_tab *tb, const char *source, int direction)
626{
627 mnt_fs *fs = NULL;
628
629 assert(tb);
630 assert(source);
631
632 if (!tb || !source)
633 return NULL;
634
635 DBG(DEBUG_TAB, fprintf(stderr,
636 "libmount: %s: lookup SOURCE: %s\n", tb->filename, source));
637
638 if (strchr(source, '=')) {
639 char *tag, *val;
640
641 if (blkid_parse_tag_string(source, &tag, &val) == 0) {
642
643 fs = mnt_tab_find_tag(tb, tag, val, direction);
644
645 free(tag);
646 free(val);
647 }
648 } else
649 fs = mnt_tab_find_srcpath(tb, source, direction);
650
651 return fs;
652}
653
6bd8b7a7
KZ
654
655/**
656 * mnt_tab_fprintf:
657 * @f: FILE
658 * @fmt: per line printf-like format string (see MNT_MFILE_PRINTFMT)
659 * @tb: tab pointer
660 *
661 * Returns 0 on success, -1 in case of error.
662 */
663int mnt_tab_fprintf(mnt_tab *tb, FILE *f, const char *fmt)
664{
665 mnt_iter itr;
666 mnt_fs *fs;
667
668 assert(f);
669 assert(fmt);
670 assert(tb);
671
672 if (!f || !fmt || !tb)
673 return -1;
674
675 mnt_reset_iter(&itr, MNT_ITER_FORWARD);
676 while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
677 if (mnt_fs_fprintf(fs, f, fmt) == -1)
678 return -1;
679 }
680
681 return 0;
682}
683
684/**
685 * mnt_tab_update_file
686 * @tb: tab pointer
687 *
688 * Writes tab to disk. Don't forget to lock the file (see mnt_lock()).
689 *
690 * Returns 0 on success, -1 in case of error.
691 */
692int mnt_tab_update_file(mnt_tab *tb)
693{
694 FILE *f = NULL;
695 char tmpname[PATH_MAX];
696 const char *filename;
697 struct stat st;
698 int fd;
699
700 assert(tb);
701 if (!tb)
702 goto error;
703
704 filename = mnt_tab_get_name(tb);
705 if (!filename)
706 goto error;
707
708 if (snprintf(tmpname, sizeof(tmpname), "%s.tmp", filename)
709 >= sizeof(tmpname))
710 goto error;
711
712 f = fopen(tmpname, "w");
713 if (!f)
714 goto error;
715
716 if (mnt_tab_fprintf(tb, f, MNT_MFILE_PRINTFMT) != 0)
717 goto error;
718
719 fd = fileno(f);
720
721 if (fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0)
722 goto error;
723
724 /* Copy uid/gid from the present file before renaming. */
725 if (stat(filename, &st) == 0) {
726 if (fchown(fd, st.st_uid, st.st_gid) < 0)
727 goto error;
728 }
729
730 fclose(f);
731 f = NULL;
732
733 if (rename(tmpname, filename) < 0)
734 goto error;
735
736 return 0;
737error:
738 if (f)
739 fclose(f);
740 return -1;
741}
742
743#ifdef TEST_PROGRAM
744int test_strerr(struct mtest *ts, int argc, char *argv[])
745{
746 char buf[BUFSIZ];
747 mnt_tab *tb;
748 int i;
749
750 tb = mnt_new_tab("-test-");
751 if (!tb)
752 goto err;
753
754 for (i = 0; i < 10; i++) {
755 mnt_fs *fs = mnt_new_fs();
756 if (!fs)
757 goto err;
758 if (i % 2)
759 fs->flags |= MNT_FS_ERROR; /* mark entry as broken */
760 fs->lineno = i+1;
761 mnt_tab_add_fs(tb, fs);
762 }
763
764 printf("\tadded %d valid lines\n", mnt_tab_get_nents(tb));
765 printf("\tadded %d broken lines\n", mnt_tab_get_nerrs(tb));
766
767 if (!mnt_tab_get_nerrs(tb)) /* report broken entries */
768 goto err;
769 mnt_tab_strerror(tb, buf, sizeof(buf));
770 printf("\t%s\n", buf);
771
772 mnt_free_tab(tb);
773 return 0;
774err:
775 return -1;
776}
777
778mnt_tab *create_tab(const char *file)
779{
780 mnt_tab *tb;
781
782 if (!file)
783 return NULL;
784 tb = mnt_new_tab(file);
785 if (!tb)
786 goto err;
787 if (mnt_tab_parse_file(tb) != 0)
788 goto err;
789 if (mnt_tab_get_nerrs(tb)) {
790 char buf[BUFSIZ];
791 mnt_tab_strerror(tb, buf, sizeof(buf));
792 fprintf(stderr, "%s\n", buf);
793 goto err;
794 }
795 return tb;
796err:
797 mnt_free_tab(tb);
798 return NULL;
799}
800
801int test_parse(struct mtest *ts, int argc, char *argv[])
802{
803 mnt_tab *tb;
efe73c3e
KZ
804 mnt_iter *itr;
805 mnt_fs *fs;
6bd8b7a7
KZ
806
807 tb = create_tab(argv[1]);
808 if (!tb)
809 return -1;
810
efe73c3e
KZ
811 itr = mnt_new_iter(MNT_ITER_FORWARD);
812 if (!itr)
813 goto err;
814 while(mnt_tab_next_fs(tb, itr, &fs) == 0)
815 mnt_fs_print_debug(fs, stdout);
816err:
817 mnt_free_iter(itr);
6bd8b7a7
KZ
818 mnt_free_tab(tb);
819 return 0;
820}
821
822int test_find(struct mtest *ts, int argc, char *argv[], int dr)
823{
824 mnt_tab *tb;
825 mnt_fs *fs = NULL;
826 mnt_cache *mpc;
827 const char *file, *find, *what;
828
829 if (argc != 4) {
830 fprintf(stderr, "try --help\n");
831 goto err;
832 }
833
834 file = argv[1], find = argv[2], what = argv[3];
835
836 tb = create_tab(file);
837 if (!tb)
838 goto err;
839
840 /* create a cache for canonicalized paths */
841 mpc = mnt_new_cache();
842 if (!mpc)
843 goto err;
844 mnt_tab_set_cache(tb, mpc);
845
846 if (strcasecmp(find, "source") == 0)
847 fs = mnt_tab_find_source(tb, what, dr);
848 else if (strcasecmp(find, "target") == 0)
849 fs = mnt_tab_find_target(tb, what, dr);
850
851 if (!fs)
852 fprintf(stderr, "%s: not found %s '%s'\n", file, find, what);
853 else {
854 const char *s = mnt_fs_get_srcpath(fs);
855 if (s)
856 printf("%s", s);
857 else {
858 const char *tag, *val;
859 mnt_fs_get_tag(fs, &tag, &val);
860 printf("%s=%s", tag, val);
861 }
862 printf("|%s|%s\n", mnt_fs_get_target(fs),
863 mnt_fs_get_optstr(fs));
864 }
865 mnt_free_tab(tb);
866 mnt_free_cache(mpc);
867 return 0;
868err:
869 return -1;
870}
871
872int test_find_bw(struct mtest *ts, int argc, char *argv[])
873{
874 return test_find(ts, argc, argv, MNT_ITER_BACKWARD);
875}
876
877int test_find_fw(struct mtest *ts, int argc, char *argv[])
878{
879 return test_find(ts, argc, argv, MNT_ITER_FORWARD);
880}
881
882int main(int argc, char *argv[])
883{
884 struct mtest tss[] = {
885 { "--strerror", test_strerr, " test tab error reporting" },
886 { "--parse", test_parse, "<file> parse and print tab" },
887 { "--find-forward", test_find_fw, "<file> <source|target> <string>" },
888 { "--find-backward", test_find_bw, "<file> <source|target> <string>" },
889 { NULL }
890 };
891
892 return mnt_run_test(tss, argc, argv);
893}
894
895#endif /* TEST_PROGRAM */