]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - libmount/src/tab.c
2 * Copyright (C) 2008-2010 Karel Zak <kzak@redhat.com>
4 * This file may be redistributed under the terms of the
5 * GNU Lesser General Public License.
10 * @title: Table of filesystems
11 * @short_description: container for entries from fstab, mtab or mountinfo
13 * Note that mnt_table_find_* functions are mount(8) compatible. These functions
14 * try to find an entry in more iterations, where the first attempt is always
15 * based on comparison with unmodified (non-canonicalized or un-evaluated)
16 * paths or tags. For example a fstab with two entries:
19 * LABEL=foo /foo auto rw
20 * /dev/foo /foo auto rw
24 * where both lines are used for the *same* device, then
27 * mnt_table_find_source(tb, "/dev/foo", &fs);
30 * will returns the second line, and
33 * mnt_table_find_source(tb, "LABEL=foo", &fs);
36 * will returns the first entry, and
39 * mnt_table_find_source(tb, "UUID=anyuuid", &fs);
42 * will return the first entry (if UUID matches with the device).
49 #include "fileutils.h"
51 static int is_mountinfo(struct libmnt_table
*tb
)
58 fs
= list_first_entry(&tb
->ents
, struct libmnt_fs
, ents
);
59 if (fs
&& mnt_fs_is_kernel(fs
) && mnt_fs_get_root(fs
))
68 * The tab is a container for struct libmnt_fs entries that usually represents a fstab,
69 * mtab or mountinfo file from your system.
71 * See also mnt_table_parse_file().
73 * Returns: newly allocated tab struct.
75 struct libmnt_table
*mnt_new_table(void)
77 struct libmnt_table
*tb
= NULL
;
79 tb
= calloc(1, sizeof(*tb
));
83 DBG(TAB
, ul_debugobj(tb
, "alloc"));
85 INIT_LIST_HEAD(&tb
->ents
);
93 * Removes all entries (filesystems) from the table. The filesystems with zero
94 * reference count will be deallocated.
96 * Returns: 0 on success or negative number in case of error.
98 int mnt_reset_table(struct libmnt_table
*tb
)
103 DBG(TAB
, ul_debugobj(tb
, "reset"));
105 while (!list_empty(&tb
->ents
)) {
106 struct libmnt_fs
*fs
= list_entry(tb
->ents
.next
,
107 struct libmnt_fs
, ents
);
108 mnt_table_remove_fs(tb
, fs
);
119 * Increments reference counter.
121 void mnt_ref_table(struct libmnt_table
*tb
)
125 /*DBG(FS, ul_debugobj(tb, "ref=%d", tb->refcount));*/
133 * De-increments reference counter, on zero the @tb is automatically
134 * deallocated by mnt_free_table().
136 void mnt_unref_table(struct libmnt_table
*tb
)
140 /*DBG(FS, ul_debugobj(tb, "unref=%d", tb->refcount));*/
141 if (tb
->refcount
<= 0)
151 * Deallocates the table. This function does not care about reference count. Don't
152 * use this function directly -- it's better to use use mnt_unref_table().
154 * The table entries (filesystems) are unrefrenced by mnt_reset_table() and
155 * cache by mnt_unref_cache().
157 void mnt_free_table(struct libmnt_table
*tb
)
163 DBG(TAB
, ul_debugobj(tb
, "free [refcount=%d]", tb
->refcount
));
165 mnt_unref_cache(tb
->cache
);
166 free(tb
->comm_intro
);
172 * mnt_table_get_nents:
173 * @tb: pointer to tab
175 * Returns: number of entries in table.
177 int mnt_table_get_nents(struct libmnt_table
*tb
)
179 return tb
? tb
->nents
: 0;
183 * mnt_table_is_empty:
184 * @tb: pointer to tab
186 * Returns: 1 if the table is without filesystems, or 0.
188 int mnt_table_is_empty(struct libmnt_table
*tb
)
191 return tb
== NULL
|| list_empty(&tb
->ents
) ? 1 : 0;
195 * mnt_table_set_userdata:
196 * @tb: pointer to tab
197 * @data: pointer to user data
199 * Sets pointer to the private user data.
201 * Returns: 0 on success or negative number in case of error.
203 int mnt_table_set_userdata(struct libmnt_table
*tb
, void *data
)
214 * mnt_table_get_userdata:
215 * @tb: pointer to tab
217 * Returns: pointer to user's data.
219 void *mnt_table_get_userdata(struct libmnt_table
*tb
)
222 return tb
? tb
->userdata
: NULL
;
226 * mnt_table_enable_comments:
227 * @tb: pointer to tab
228 * @enable: TRUE or FALSE
230 * Enables parsing of comments.
232 * The initial (intro) file comment is accessible by
233 * mnt_table_get_intro_comment(). The intro and the comment of the first fstab
234 * entry has to be separated by blank line. The filesystem comments are
235 * accessible by mnt_fs_get_comment(). The trailing fstab comment is accessible
236 * by mnt_table_get_trailing_comment().
244 * # this comments belongs to the first fs
245 * LABEL=foo /mnt/foo auto defaults 1 2
246 * # this comments belongs to the second fs
247 * LABEL=bar /mnt/bar auto defaults 1 2
252 void mnt_table_enable_comments(struct libmnt_table
*tb
, int enable
)
260 * mnt_table_with_comments:
261 * @tb: pointer to table
263 * Returns: 1 if comments parsing is enabled, or 0.
265 int mnt_table_with_comments(struct libmnt_table
*tb
)
268 return tb
? tb
->comms
: 0;
272 * mnt_table_get_intro_comment:
273 * @tb: pointer to tab
275 * Returns: initial comment in tb
277 const char *mnt_table_get_intro_comment(struct libmnt_table
*tb
)
280 return tb
? tb
->comm_intro
: NULL
;
284 * mnt_table_set_into_comment:
285 * @tb: pointer to tab
286 * @comm: comment or NULL
288 * Sets the initial comment in tb.
290 * Returns: 0 on success or negative number in case of error.
292 int mnt_table_set_intro_comment(struct libmnt_table
*tb
, const char *comm
)
304 free(tb
->comm_intro
);
310 * mnt_table_append_into_comment:
311 * @tb: pointer to tab
312 * @comm: comment of NULL
314 * Appends the initial comment in tb.
316 * Returns: 0 on success or negative number in case of error.
318 int mnt_table_append_intro_comment(struct libmnt_table
*tb
, const char *comm
)
323 return append_string(&tb
->comm_intro
, comm
);
327 * mnt_table_get_trailing_comment:
328 * @tb: pointer to tab
330 * Returns: table trailing comment
332 const char *mnt_table_get_trailing_comment(struct libmnt_table
*tb
)
335 return tb
? tb
->comm_tail
: NULL
;
339 * mnt_table_set_trailing_comment
340 * @tb: pointer to tab
341 * @comm: comment string
343 * Sets the trailing comment in table.
345 * Returns: 0 on success or negative number in case of error.
347 int mnt_table_set_trailing_comment(struct libmnt_table
*tb
, const char *comm
)
365 * mnt_table_append_trailing_comment:
366 * @tb: pointer to tab
367 * @comm: comment of NULL
369 * Appends to the trailing table comment.
371 * Returns: 0 on success or negative number in case of error.
373 int mnt_table_append_trailing_comment(struct libmnt_table
*tb
, const char *comm
)
378 return append_string(&tb
->comm_tail
, comm
);
382 * mnt_table_set_cache:
383 * @tb: pointer to tab
384 * @mpc: pointer to struct libmnt_cache instance
386 * Sets up a cache for canonicalized paths and evaluated tags (LABEL/UUID). The
387 * cache is recommended for mnt_table_find_*() functions.
389 * The cache could be shared between more tabs. Be careful when you share the
390 * same cache between more threads -- currently the cache does not provide any
393 * This function increments cache reference counter. It's recomented to use
394 * mnt_unref_cache() after mnt_table_set_cache() if you want to keep the cache
395 * referenced by @tb only.
397 * See also mnt_new_cache().
399 * Returns: 0 on success or negative number in case of error.
401 int mnt_table_set_cache(struct libmnt_table
*tb
, struct libmnt_cache
*mpc
)
407 mnt_ref_cache(mpc
); /* new */
408 mnt_unref_cache(tb
->cache
); /* old */
414 * mnt_table_get_cache:
415 * @tb: pointer to tab
417 * Returns: pointer to struct libmnt_cache instance or NULL.
419 struct libmnt_cache
*mnt_table_get_cache(struct libmnt_table
*tb
)
422 return tb
? tb
->cache
: NULL
;
430 * Adds a new entry to tab and increment @fs reference counter. Don't forget to
431 * use mnt_unref_fs() after mnt_table_add_fs() you want to keep the @fs
432 * referenced by the table only.
434 * Returns: 0 on success or negative number in case of error.
436 int mnt_table_add_fs(struct libmnt_table
*tb
, struct libmnt_fs
*fs
)
445 list_add_tail(&fs
->ents
, &tb
->ents
);
448 DBG(TAB
, ul_debugobj(tb
, "add entry: %s %s",
449 mnt_fs_get_source(fs
), mnt_fs_get_target(fs
)));
454 * mnt_table_remove_fs:
458 * Removes the @fs from the table and de-increment reference counter of the @fs. The
459 * filesystem with zero reference counter will be deallocated. Don't forget to use
460 * mnt_ref_fs() before call mnt_table_remove_fs() if you want to use @fs later.
462 * Returns: 0 on success or negative number in case of error.
464 int mnt_table_remove_fs(struct libmnt_table
*tb
, struct libmnt_fs
*fs
)
473 INIT_LIST_HEAD(&fs
->ents
); /* otherwise FS still points to the list */
481 * mnt_table_get_root_fs:
482 * @tb: mountinfo file (/proc/self/mountinfo)
483 * @root: returns pointer to the root filesystem (/)
485 * The function uses the parent ID from the mountinfo file to determine the root filesystem
486 * (the filesystem with the smallest ID). The function is designed mostly for
487 * applications where it is necessary to sort mountpoints by IDs to get the tree
488 * of the mountpoints (e.g. findmnt default output).
490 * If you're not sure, then use
492 * mnt_table_find_target(tb, "/", MNT_ITER_BACKWARD);
494 * this is more robust and usable for arbitrary tab files (including fstab).
496 * Returns: 0 on success or negative number in case of error.
498 int mnt_table_get_root_fs(struct libmnt_table
*tb
, struct libmnt_fs
**root
)
500 struct libmnt_iter itr
;
501 struct libmnt_fs
*fs
;
507 if (!tb
|| !root
|| !is_mountinfo(tb
))
510 DBG(TAB
, ul_debugobj(tb
, "lookup root fs"));
514 mnt_reset_iter(&itr
, MNT_ITER_FORWARD
);
515 while(mnt_table_next_fs(tb
, &itr
, &fs
) == 0) {
516 int id
= mnt_fs_get_parent_id(fs
);
518 if (!*root
|| id
< root_id
) {
524 return *root
? 0 : -EINVAL
;
528 * mnt_table_next_child_fs:
529 * @tb: mountinfo file (/proc/self/mountinfo)
531 * @parent: parental FS
532 * @chld: returns the next child filesystem
534 * Note that filesystems are returned in the order of mounting (according to
535 * IDs in /proc/self/mountinfo).
537 * Returns: 0 on success, negative number in case of error or 1 at the end of list.
539 int mnt_table_next_child_fs(struct libmnt_table
*tb
, struct libmnt_iter
*itr
,
540 struct libmnt_fs
*parent
, struct libmnt_fs
**chld
)
542 struct libmnt_fs
*fs
;
543 int parent_id
, lastchld_id
= 0, chld_id
= 0;
545 if (!tb
|| !itr
|| !parent
|| !is_mountinfo(tb
))
548 DBG(TAB
, ul_debugobj(tb
, "lookup next child of '%s'",
549 mnt_fs_get_target(parent
)));
551 parent_id
= mnt_fs_get_id(parent
);
553 /* get ID of the previously returned child */
554 if (itr
->head
&& itr
->p
!= itr
->head
) {
555 MNT_ITER_ITERATE(itr
, fs
, struct libmnt_fs
, ents
);
556 lastchld_id
= mnt_fs_get_id(fs
);
561 mnt_reset_iter(itr
, MNT_ITER_FORWARD
);
562 while(mnt_table_next_fs(tb
, itr
, &fs
) == 0) {
565 if (mnt_fs_get_parent_id(fs
) != parent_id
)
568 id
= mnt_fs_get_id(fs
);
570 /* avoid an infinite loop. This only happens in rare cases
571 * such as in early userspace when the rootfs is its own parent */
575 if ((!lastchld_id
|| id
> lastchld_id
) &&
576 (!*chld
|| id
< chld_id
)) {
583 return 1; /* end of iterator */
585 /* set the iterator to the @chld for the next call */
586 mnt_table_set_iter(tb
, itr
, *chld
);
595 * @fs: returns the next tab entry
597 * Returns: 0 on success, negative number in case of error or 1 at the end of list.
602 * while(mnt_table_next_fs(tb, itr, &fs) == 0) {
603 * const char *dir = mnt_fs_get_target(fs);
604 * printf("mount point: %s\n", dir);
609 * lists all mountpoints from fstab in reverse order.
611 int mnt_table_next_fs(struct libmnt_table
*tb
, struct libmnt_iter
*itr
, struct libmnt_fs
**fs
)
619 if (!tb
|| !itr
|| !fs
)
624 MNT_ITER_INIT(itr
, &tb
->ents
);
625 if (itr
->p
!= itr
->head
) {
626 MNT_ITER_ITERATE(itr
, *fs
, struct libmnt_fs
, ents
);
634 * mnt_table_first_fs:
636 * @fs: returns the first tab entry
638 * Returns: 0 on success, negative number in case of error or 1 at the end of list.
640 int mnt_table_first_fs(struct libmnt_table
*tb
, struct libmnt_fs
**fs
)
647 if (list_empty(&tb
->ents
))
649 *fs
= list_first_entry(&tb
->ents
, struct libmnt_fs
, ents
);
656 * @fs: returns the last tab entry
658 * Returns: 0 on success, negative number in case of error or 1 at the end of list.
660 int mnt_table_last_fs(struct libmnt_table
*tb
, struct libmnt_fs
**fs
)
667 if (list_empty(&tb
->ents
))
669 *fs
= list_last_entry(&tb
->ents
, struct libmnt_fs
, ents
);
674 * mnt_table_find_next_fs:
677 * @match_func: function returning 1 or 0
678 * @userdata: extra data for match_func
679 * @fs: returns pointer to the next matching table entry
681 * This function allows searching in @tb.
683 * Returns: negative number in case of error, 1 at end of table or 0 o success.
685 int mnt_table_find_next_fs(struct libmnt_table
*tb
, struct libmnt_iter
*itr
,
686 int (*match_func
)(struct libmnt_fs
*, void *), void *userdata
,
687 struct libmnt_fs
**fs
)
689 if (!tb
|| !itr
|| !fs
|| !match_func
)
692 DBG(TAB
, ul_debugobj(tb
, "lookup next fs"));
695 MNT_ITER_INIT(itr
, &tb
->ents
);
698 if (itr
->p
!= itr
->head
)
699 MNT_ITER_ITERATE(itr
, *fs
, struct libmnt_fs
, ents
);
703 if (match_func(*fs
, userdata
))
711 static int mnt_table_move_parent(struct libmnt_table
*tb
, int oldid
, int newid
)
713 struct libmnt_iter itr
;
714 struct libmnt_fs
*fs
;
720 if (list_empty(&tb
->ents
))
723 DBG(TAB
, ul_debugobj(tb
, "moving parent ID from %d -> %d", oldid
, newid
));
724 mnt_reset_iter(&itr
, MNT_ITER_FORWARD
);
726 while (mnt_table_next_fs(tb
, &itr
, &fs
) == 0) {
727 if (fs
->parent
== oldid
)
737 * @cmp: function to compare filesystems
739 * This function de-duplicate the @tb, but does not change order of the
740 * filesystems. The @cmp function has to return 0 if the filesystems are
741 * equal, otherwise non-zero.
743 * The default is to keep in the table later mounted filesystems (function uses
744 * backward mode iterator).
746 * @MNT_UNIQ_FORWARD: remove later mounted filesystems
747 * @MNT_UNIQ_KEEPTREE: keep parent->id relation ship stil valid
749 * Returns: negative number in case of error, or 0 o success.
751 int mnt_table_uniq_fs(struct libmnt_table
*tb
, int flags
,
752 int (*cmp
)(struct libmnt_table
*,
756 struct libmnt_iter itr
;
757 struct libmnt_fs
*fs
;
758 int direction
= MNT_ITER_BACKWARD
;
765 if (list_empty(&tb
->ents
))
768 if (flags
& MNT_UNIQ_FORWARD
)
769 direction
= MNT_ITER_FORWARD
;
771 DBG(TAB
, ul_debugobj(tb
, "de-duplicate"));
772 mnt_reset_iter(&itr
, direction
);
774 if ((flags
& MNT_UNIQ_KEEPTREE
) && !is_mountinfo(tb
))
775 flags
&= ~MNT_UNIQ_KEEPTREE
;
777 while (mnt_table_next_fs(tb
, &itr
, &fs
) == 0) {
779 struct libmnt_iter xtr
;
782 mnt_reset_iter(&xtr
, direction
);
783 while (want
&& mnt_table_next_fs(tb
, &xtr
, &x
) == 0) {
786 want
= cmp(tb
, x
, fs
) != 0;
790 if (flags
& MNT_UNIQ_KEEPTREE
)
791 mnt_table_move_parent(tb
, mnt_fs_get_id(fs
),
792 mnt_fs_get_parent_id(fs
));
794 DBG(TAB
, ul_debugobj(tb
, "remove duplicate %s",
795 mnt_fs_get_target(fs
)));
796 mnt_table_remove_fs(tb
, fs
);
804 * mnt_table_set_iter:
809 * Sets @iter to the position of @fs in the file @tb.
811 * Returns: 0 on success, negative number in case of error.
813 int mnt_table_set_iter(struct libmnt_table
*tb
, struct libmnt_iter
*itr
, struct libmnt_fs
*fs
)
819 if (!tb
|| !itr
|| !fs
)
822 MNT_ITER_INIT(itr
, &tb
->ents
);
829 * mnt_table_find_mountpoint:
832 * @direction: MNT_ITER_{FORWARD,BACKWARD}
834 * Same as mnt_get_mountpoint(), except this function does not rely on
837 * Returns: a tab entry or NULL.
839 struct libmnt_fs
*mnt_table_find_mountpoint(struct libmnt_table
*tb
,
845 if (!tb
|| !path
|| !*path
)
847 if (direction
!= MNT_ITER_FORWARD
&& direction
!= MNT_ITER_BACKWARD
)
850 DBG(TAB
, ul_debugobj(tb
, "lookup MOUNTPOINT: '%s'", path
));
858 struct libmnt_fs
*fs
;
860 fs
= mnt_table_find_target(tb
, mnt
, direction
);
866 p
= stripoff_last_component(mnt
);
869 } while (mnt
&& *(mnt
+ 1) != '\0');
872 return mnt_table_find_target(tb
, "/", direction
);
876 * mnt_table_find_target:
878 * @path: mountpoint directory
879 * @direction: MNT_ITER_{FORWARD,BACKWARD}
881 * Try to lookup an entry in the given tab, three iterations are possible, the first
882 * with @path, the second with realpath(@path) and the third with realpath(@path)
883 * against realpath(fs->target). The 2nd and 3rd iterations are not performed when
884 * the @tb cache is not set (see mnt_table_set_cache()). If
885 * mnt_cache_set_targets(cache, mtab) was called, the 3rd iteration skips any
886 * @fs->target found in @mtab (see mnt_resolve_target()).
888 * Returns: a tab entry or NULL.
890 struct libmnt_fs
*mnt_table_find_target(struct libmnt_table
*tb
, const char *path
, int direction
)
892 struct libmnt_iter itr
;
893 struct libmnt_fs
*fs
= NULL
;
899 if (!tb
|| !path
|| !*path
)
901 if (direction
!= MNT_ITER_FORWARD
&& direction
!= MNT_ITER_BACKWARD
)
904 DBG(TAB
, ul_debugobj(tb
, "lookup TARGET: '%s'", path
));
907 mnt_reset_iter(&itr
, direction
);
908 while(mnt_table_next_fs(tb
, &itr
, &fs
) == 0) {
909 if (mnt_fs_streq_target(fs
, path
))
912 if (!tb
->cache
|| !(cn
= mnt_resolve_path(path
, tb
->cache
)))
915 DBG(TAB
, ul_debugobj(tb
, "lookup canonical TARGET: '%s'", cn
));
917 /* canonicalized paths in struct libmnt_table */
918 mnt_reset_iter(&itr
, direction
);
919 while(mnt_table_next_fs(tb
, &itr
, &fs
) == 0) {
920 if (mnt_fs_streq_target(fs
, cn
))
924 /* non-canonicaled path in struct libmnt_table
925 * -- note that mountpoint in /proc/self/mountinfo is already
926 * canonicalized by the kernel
928 mnt_reset_iter(&itr
, direction
);
929 while(mnt_table_next_fs(tb
, &itr
, &fs
) == 0) {
933 || mnt_fs_is_swaparea(fs
)
934 || mnt_fs_is_kernel(fs
)
935 || (*fs
->target
== '/' && *(fs
->target
+ 1) == '\0'))
938 p
= mnt_resolve_target(fs
->target
, tb
->cache
);
939 /* both canonicalized, strcmp() is fine here */
940 if (p
&& strcmp(cn
, p
) == 0)
947 * mnt_table_find_srcpath:
949 * @path: source path (devname or dirname) or NULL
950 * @direction: MNT_ITER_{FORWARD,BACKWARD}
952 * Try to lookup an entry in the given tab, four iterations are possible, the first
953 * with @path, the second with realpath(@path), the third with tags (LABEL, UUID, ..)
954 * from @path and the fourth with realpath(@path) against realpath(entry->srcpath).
956 * The 2nd, 3rd and 4th iterations are not performed when the @tb cache is not
957 * set (see mnt_table_set_cache()).
959 * Note that NULL is a valid source path; it will be replaced with "none". The
960 * "none" is used in /proc/{mounts,self/mountinfo} for pseudo filesystems.
962 * Returns: a tab entry or NULL.
964 struct libmnt_fs
*mnt_table_find_srcpath(struct libmnt_table
*tb
, const char *path
, int direction
)
966 struct libmnt_iter itr
;
967 struct libmnt_fs
*fs
= NULL
;
968 int ntags
= 0, nents
;
973 if (!tb
|| !path
|| !*path
)
975 if (direction
!= MNT_ITER_FORWARD
&& direction
!= MNT_ITER_BACKWARD
)
978 DBG(TAB
, ul_debugobj(tb
, "lookup SRCPATH: '%s'", path
));
981 mnt_reset_iter(&itr
, direction
);
982 while(mnt_table_next_fs(tb
, &itr
, &fs
) == 0) {
983 if (mnt_fs_streq_srcpath(fs
, path
))
985 if (mnt_fs_get_tag(fs
, NULL
, NULL
) == 0)
989 if (!path
|| !tb
->cache
|| !(cn
= mnt_resolve_path(path
, tb
->cache
)))
992 DBG(TAB
, ul_debugobj(tb
, "lookup canonical SRCPATH: '%s'", cn
));
994 nents
= mnt_table_get_nents(tb
);
996 /* canonicalized paths in struct libmnt_table */
998 mnt_reset_iter(&itr
, direction
);
999 while(mnt_table_next_fs(tb
, &itr
, &fs
) == 0) {
1000 if (mnt_fs_streq_srcpath(fs
, cn
))
1007 int rc
= mnt_cache_read_tags(tb
->cache
, cn
);
1009 mnt_reset_iter(&itr
, direction
);
1012 /* @path's TAGs are in the cache */
1013 while(mnt_table_next_fs(tb
, &itr
, &fs
) == 0) {
1016 if (mnt_fs_get_tag(fs
, &t
, &v
))
1019 if (mnt_cache_device_has_tag(tb
->cache
, cn
, t
, v
))
1022 } else if (rc
< 0 && errno
== EACCES
) {
1023 /* @path is inaccessible, try evaluating all TAGs in @tb
1024 * by udev symlinks -- this could be expensive on systems
1025 * with a huge fstab/mtab */
1026 while(mnt_table_next_fs(tb
, &itr
, &fs
) == 0) {
1027 const char *t
, *v
, *x
;
1028 if (mnt_fs_get_tag(fs
, &t
, &v
))
1030 x
= mnt_resolve_tag(t
, v
, tb
->cache
);
1032 /* both canonicalized, strcmp() is fine here */
1033 if (x
&& strcmp(x
, cn
) == 0)
1039 /* non-canonicalized paths in struct libmnt_table */
1040 if (ntags
<= nents
) {
1041 mnt_reset_iter(&itr
, direction
);
1042 while(mnt_table_next_fs(tb
, &itr
, &fs
) == 0) {
1043 if (mnt_fs_is_netfs(fs
) || mnt_fs_is_pseudofs(fs
))
1045 p
= mnt_fs_get_srcpath(fs
);
1047 p
= mnt_resolve_path(p
, tb
->cache
);
1049 /* both canonicalized, strcmp() is fine here */
1050 if (p
&& strcmp(p
, cn
) == 0)
1060 * mnt_table_find_tag:
1062 * @tag: tag name (e.g "LABEL", "UUID", ...)
1064 * @direction: MNT_ITER_{FORWARD,BACKWARD}
1066 * Try to lookup an entry in the given tab, the first attempt is to lookup by @tag and
1067 * @val, for the second attempt the tag is evaluated (converted to the device
1068 * name) and mnt_table_find_srcpath() is performed. The second attempt is not
1069 * performed when @tb cache is not set (see mnt_table_set_cache()).
1071 * Returns: a tab entry or NULL.
1073 struct libmnt_fs
*mnt_table_find_tag(struct libmnt_table
*tb
, const char *tag
,
1074 const char *val
, int direction
)
1076 struct libmnt_iter itr
;
1077 struct libmnt_fs
*fs
= NULL
;
1083 if (!tb
|| !tag
|| !*tag
|| !val
)
1085 if (direction
!= MNT_ITER_FORWARD
&& direction
!= MNT_ITER_BACKWARD
)
1088 DBG(TAB
, ul_debugobj(tb
, "lookup by TAG: %s %s", tag
, val
));
1090 /* look up by TAG */
1091 mnt_reset_iter(&itr
, direction
);
1092 while(mnt_table_next_fs(tb
, &itr
, &fs
) == 0) {
1093 if (fs
->tagname
&& fs
->tagval
&&
1094 strcmp(fs
->tagname
, tag
) == 0 &&
1095 strcmp(fs
->tagval
, val
) == 0)
1100 /* look up by device name */
1101 char *cn
= mnt_resolve_tag(tag
, val
, tb
->cache
);
1103 return mnt_table_find_srcpath(tb
, cn
, direction
);
1109 * mnt_table_find_source:
1111 * @source: TAG or path
1112 * @direction: MNT_ITER_{FORWARD,BACKWARD}
1114 * This is a high-level API for mnt_table_find_{srcpath,tag}. You needn't care
1115 * about the @source format (device, LABEL, UUID, ...). This function parses
1116 * the @source and calls mnt_table_find_tag() or mnt_table_find_srcpath().
1118 * Returns: a tab entry or NULL.
1120 struct libmnt_fs
*mnt_table_find_source(struct libmnt_table
*tb
,
1121 const char *source
, int direction
)
1123 struct libmnt_fs
*fs
;
1124 char *t
= NULL
, *v
= NULL
;
1130 if (direction
!= MNT_ITER_FORWARD
&& direction
!= MNT_ITER_BACKWARD
)
1133 DBG(TAB
, ul_debugobj(tb
, "lookup SOURCE: '%s'", source
));
1135 if (blkid_parse_tag_string(source
, &t
, &v
) || !mnt_valid_tagname(t
))
1136 fs
= mnt_table_find_srcpath(tb
, source
, direction
);
1138 fs
= mnt_table_find_tag(tb
, t
, v
, direction
);
1147 * mnt_table_find_pair
1149 * @source: TAG or path
1150 * @target: mountpoint
1151 * @direction: MNT_ITER_{FORWARD,BACKWARD}
1153 * This function is implemented by mnt_fs_match_source() and
1154 * mnt_fs_match_target() functions. It means that this is more expensive than
1155 * others mnt_table_find_* function, because every @tab entry is fully evaluated.
1157 * Returns: a tab entry or NULL.
1159 struct libmnt_fs
*mnt_table_find_pair(struct libmnt_table
*tb
, const char *source
,
1160 const char *target
, int direction
)
1162 struct libmnt_fs
*fs
= NULL
;
1163 struct libmnt_iter itr
;
1168 if (!tb
|| !target
|| !*target
|| !source
|| !*source
)
1170 if (direction
!= MNT_ITER_FORWARD
&& direction
!= MNT_ITER_BACKWARD
)
1173 DBG(TAB
, ul_debugobj(tb
, "lookup SOURCE: %s TARGET: %s", source
, target
));
1175 mnt_reset_iter(&itr
, direction
);
1176 while(mnt_table_next_fs(tb
, &itr
, &fs
) == 0) {
1178 if (mnt_fs_match_target(fs
, target
, tb
->cache
) &&
1179 mnt_fs_match_source(fs
, source
, tb
->cache
))
1187 * mnt_table_find_devno
1188 * @tb: /proc/self/mountinfo
1189 * @devno: device number
1190 * @direction: MNT_ITER_{FORWARD,BACKWARD}
1192 * Note that zero could be a valid device number for the root pseudo filesystem (e.g.
1195 * Returns: a tab entry or NULL.
1197 struct libmnt_fs
*mnt_table_find_devno(struct libmnt_table
*tb
,
1198 dev_t devno
, int direction
)
1200 struct libmnt_fs
*fs
= NULL
;
1201 struct libmnt_iter itr
;
1207 if (direction
!= MNT_ITER_FORWARD
&& direction
!= MNT_ITER_BACKWARD
)
1210 DBG(TAB
, ul_debugobj(tb
, "lookup DEVNO: %d", (int) devno
));
1212 mnt_reset_iter(&itr
, direction
);
1214 while(mnt_table_next_fs(tb
, &itr
, &fs
) == 0) {
1215 if (mnt_fs_get_devno(fs
) == devno
)
1223 * tb: /proc/self/mountinfo
1225 * mountflags: MS_BIND or 0
1226 * fsroot: fs-root that will probably be used in the mountinfo file
1227 * for @fs after mount(2)
1229 * For btrfs subvolumes this function returns NULL, but @fsroot properly set.
1231 * Returns: entry from @tb that will be used as a source for @fs if the @fs is
1234 * Don't export to library API!
1236 struct libmnt_fs
*mnt_table_get_fs_root(struct libmnt_table
*tb
,
1237 struct libmnt_fs
*fs
,
1238 unsigned long mountflags
,
1241 char *root
= NULL
, *mnt
= NULL
;
1243 struct libmnt_fs
*src_fs
= NULL
;
1248 DBG(TAB
, ul_debug("lookup fs-root for '%s'", mnt_fs_get_source(fs
)));
1250 fstype
= mnt_fs_get_fstype(fs
);
1252 if (tb
&& (mountflags
& MS_BIND
)) {
1253 const char *src
, *src_root
;
1256 DBG(TAB
, ul_debug("fs-root for bind"));
1258 src
= xsrc
= mnt_resolve_spec(mnt_fs_get_source(fs
), tb
->cache
);
1260 mnt
= mnt_get_mountpoint(src
);
1262 root
= mnt_get_fs_root(src
, mnt
);
1264 if (xsrc
&& !tb
->cache
) {
1271 src_fs
= mnt_table_find_target(tb
, mnt
, MNT_ITER_BACKWARD
);
1273 DBG(TAB
, ul_debug("not found '%s' in mountinfo -- using default", mnt
));
1277 /* on btrfs the subvolume is used as fs-root in
1278 * /proc/self/mountinfo, so we have to get the original subvolume
1279 * name from src_fs and prepend the subvolume name to the
1282 src_root
= mnt_fs_get_root(src_fs
);
1283 if (src_root
&& !startswith(root
, src_root
)) {
1284 size_t sz
= strlen(root
) + strlen(src_root
) + 1;
1285 char *tmp
= malloc(sz
);
1289 snprintf(tmp
, sz
, "%s%s", src_root
, root
);
1296 * btrfs-subvolume mount -- get subvolume name and use it as a root-fs path
1298 else if (fstype
&& !strcmp(fstype
, "btrfs")) {
1299 char *vol
= NULL
, *p
;
1300 size_t sz
, volsz
= 0;
1302 if (mnt_fs_get_option(fs
, "subvol", &vol
, &volsz
))
1305 DBG(TAB
, ul_debug("setting FS root: btrfs subvol"));
1310 root
= malloc(sz
+ 1);
1316 memcpy(p
, vol
, volsz
);
1317 *(root
+ sz
) = '\0';
1327 DBG(TAB
, ul_debug("FS root result: %s", root
));
1338 * mnt_table_is_fs__mounted:
1339 * @tb: /proc/self/mountinfo file
1340 * @fstab_fs: /etc/fstab entry
1342 * Checks if the @fstab_fs entry is already in the @tb table. The "swap" is
1343 * ignored. This function explicitly compares the source, target and root of the
1346 * Note that source and target are canonicalized only if a cache for @tb is
1347 * defined (see mnt_table_set_cache()). The target canonicalization may
1348 * trigger automount on autofs mountpoints!
1350 * Don't use it if you want to know if a device is mounted, just use
1351 * mnt_table_find_source() on the device.
1353 * This function is designed mostly for "mount -a".
1357 int mnt_table_is_fs_mounted(struct libmnt_table
*tb
, struct libmnt_fs
*fstab_fs
)
1359 struct libmnt_iter itr
;
1360 struct libmnt_fs
*fs
;
1363 const char *src
= NULL
, *tgt
= NULL
;
1371 DBG(FS
, ul_debugobj(fstab_fs
, "is FS mounted? [target=%s]",
1372 mnt_fs_get_target(fstab_fs
)));
1374 if (mnt_fs_is_swaparea(fstab_fs
) || mnt_table_is_empty(tb
)) {
1375 DBG(FS
, ul_debugobj(fstab_fs
, "- ignore (swap or no data)"));
1379 if (is_mountinfo(tb
)) {
1380 /* @tb is mountinfo, so we can try to use fs-roots */
1381 struct libmnt_fs
*rootfs
;
1384 if (mnt_fs_get_option(fstab_fs
, "bind", NULL
, NULL
) == 0)
1387 rootfs
= mnt_table_get_fs_root(tb
, fstab_fs
, flags
, &root
);
1389 src
= mnt_fs_get_srcpath(rootfs
);
1393 src
= mnt_fs_get_source(fstab_fs
);
1395 if (src
&& tb
->cache
&& !mnt_fs_is_pseudofs(fstab_fs
))
1396 src
= mnt_resolve_spec(src
, tb
->cache
);
1401 devno
= mnt_fs_get_devno(fstab_fs
);
1402 if (!devno
&& stat(src
, &st
) == 0 && S_ISBLK(st
.st_mode
))
1406 tgt
= mnt_fs_get_target(fstab_fs
);
1409 DBG(FS
, ul_debugobj(fstab_fs
, "- ignore (no source/target)"));
1412 mnt_reset_iter(&itr
, MNT_ITER_FORWARD
);
1414 while (mnt_table_next_fs(tb
, &itr
, &fs
) == 0) {
1416 int eq
= mnt_fs_streq_srcpath(fs
, src
);
1418 if (!eq
&& devno
&& mnt_fs_get_devno(fs
) == devno
)
1422 /* The source does not match. Maybe the source is a loop
1423 * device backing file.
1425 uint64_t offset
= 0;
1430 if (!mnt_fs_is_kernel(fs
) ||
1431 !mnt_fs_get_srcpath(fs
) ||
1432 !startswith(mnt_fs_get_srcpath(fs
), "/dev/loop"))
1433 continue; /* does not look like loopdev */
1435 if (mnt_fs_get_option(fstab_fs
, "offset", &val
, &len
) == 0 &&
1436 mnt_parse_offset(val
, len
, &offset
)) {
1437 DBG(FS
, ul_debugobj(fstab_fs
, "failed to parse offset="));
1440 flags
= LOOPDEV_FL_OFFSET
;
1443 if (loopdev_is_used(mnt_fs_get_srcpath(fs
), src
, offset
, flags
))
1449 const char *r
= mnt_fs_get_root(fs
);
1450 if (!r
|| strcmp(r
, root
) != 0)
1455 * Compare target, try to minimize the number of situations when we
1456 * need to canonicalize the path to avoid readlink() on
1460 if (mnt_fs_streq_target(fs
, tgt
))
1463 xtgt
= mnt_resolve_path(tgt
, tb
->cache
);
1465 if (xtgt
&& mnt_fs_streq_target(fs
, xtgt
))
1470 rc
= 1; /* success */
1474 DBG(TAB
, ul_debugobj(tb
, "mnt_table_is_fs_mounted: %s [rc=%d]", src
, rc
));
1479 #include "pathnames.h"
1481 static int parser_errcb(struct libmnt_table
*tb
, const char *filename
, int line
)
1483 fprintf(stderr
, "%s:%d: parse error\n", filename
, line
);
1485 return 1; /* all errors are recoverable -- this is the default */
1488 struct libmnt_table
*create_table(const char *file
, int comments
)
1490 struct libmnt_table
*tb
;
1494 tb
= mnt_new_table();
1498 mnt_table_enable_comments(tb
, comments
);
1499 mnt_table_set_parser_errcb(tb
, parser_errcb
);
1501 if (mnt_table_parse_file(tb
, file
) != 0)
1505 fprintf(stderr
, "%s: parsing failed\n", file
);
1506 mnt_unref_table(tb
);
1510 int test_copy_fs(struct libmnt_test
*ts
, int argc
, char *argv
[])
1512 struct libmnt_table
*tb
;
1513 struct libmnt_fs
*fs
;
1516 tb
= create_table(argv
[1], FALSE
);
1520 fs
= mnt_table_find_target(tb
, "/", MNT_ITER_FORWARD
);
1524 printf("ORIGINAL:\n");
1525 mnt_fs_print_debug(fs
, stdout
);
1527 fs
= mnt_copy_fs(NULL
, fs
);
1532 mnt_fs_print_debug(fs
, stdout
);
1536 mnt_unref_table(tb
);
1540 int test_parse(struct libmnt_test
*ts
, int argc
, char *argv
[])
1542 struct libmnt_table
*tb
= NULL
;
1543 struct libmnt_iter
*itr
= NULL
;
1544 struct libmnt_fs
*fs
;
1546 int parse_comments
= FALSE
;
1548 if (argc
== 3 && !strcmp(argv
[2], "--comments"))
1549 parse_comments
= TRUE
;
1551 tb
= create_table(argv
[1], parse_comments
);
1555 itr
= mnt_new_iter(MNT_ITER_FORWARD
);
1559 if (mnt_table_get_intro_comment(tb
))
1560 fprintf(stdout
, "Initial comment:\n\"%s\"\n",
1561 mnt_table_get_intro_comment(tb
));
1563 while(mnt_table_next_fs(tb
, itr
, &fs
) == 0)
1564 mnt_fs_print_debug(fs
, stdout
);
1566 if (mnt_table_get_trailing_comment(tb
))
1567 fprintf(stdout
, "Trailing comment:\n\"%s\"\n",
1568 mnt_table_get_trailing_comment(tb
));
1572 mnt_unref_table(tb
);
1576 int test_find(struct libmnt_test
*ts
, int argc
, char *argv
[], int dr
)
1578 struct libmnt_table
*tb
;
1579 struct libmnt_fs
*fs
= NULL
;
1580 struct libmnt_cache
*mpc
= NULL
;
1581 const char *file
, *find
, *what
;
1585 fprintf(stderr
, "try --help\n");
1589 file
= argv
[1], find
= argv
[2], what
= argv
[3];
1591 tb
= create_table(file
, FALSE
);
1595 /* create a cache for canonicalized paths */
1596 mpc
= mnt_new_cache();
1599 mnt_table_set_cache(tb
, mpc
);
1600 mnt_unref_cache(mpc
);
1602 if (strcasecmp(find
, "source") == 0)
1603 fs
= mnt_table_find_source(tb
, what
, dr
);
1604 else if (strcasecmp(find
, "target") == 0)
1605 fs
= mnt_table_find_target(tb
, what
, dr
);
1608 fprintf(stderr
, "%s: not found %s '%s'\n", file
, find
, what
);
1610 mnt_fs_print_debug(fs
, stdout
);
1614 mnt_unref_table(tb
);
1618 int test_find_bw(struct libmnt_test
*ts
, int argc
, char *argv
[])
1620 return test_find(ts
, argc
, argv
, MNT_ITER_BACKWARD
);
1623 int test_find_fw(struct libmnt_test
*ts
, int argc
, char *argv
[])
1625 return test_find(ts
, argc
, argv
, MNT_ITER_FORWARD
);
1628 int test_find_pair(struct libmnt_test
*ts
, int argc
, char *argv
[])
1630 struct libmnt_table
*tb
;
1631 struct libmnt_fs
*fs
;
1632 struct libmnt_cache
*mpc
= NULL
;
1635 tb
= create_table(argv
[1], FALSE
);
1638 mpc
= mnt_new_cache();
1641 mnt_table_set_cache(tb
, mpc
);
1642 mnt_unref_cache(mpc
);
1644 fs
= mnt_table_find_pair(tb
, argv
[2], argv
[3], MNT_ITER_FORWARD
);
1648 mnt_fs_print_debug(fs
, stdout
);
1651 mnt_unref_table(tb
);
1655 int test_find_mountpoint(struct libmnt_test
*ts
, int argc
, char *argv
[])
1657 struct libmnt_table
*tb
;
1658 struct libmnt_fs
*fs
;
1659 struct libmnt_cache
*mpc
= NULL
;
1662 tb
= mnt_new_table_from_file(_PATH_PROC_MOUNTINFO
);
1665 mpc
= mnt_new_cache();
1668 mnt_table_set_cache(tb
, mpc
);
1669 mnt_unref_cache(mpc
);
1671 fs
= mnt_table_find_mountpoint(tb
, argv
[1], MNT_ITER_BACKWARD
);
1675 mnt_fs_print_debug(fs
, stdout
);
1678 mnt_unref_table(tb
);
1682 static int test_is_mounted(struct libmnt_test
*ts
, int argc
, char *argv
[])
1684 struct libmnt_table
*tb
= NULL
, *fstab
= NULL
;
1685 struct libmnt_fs
*fs
;
1686 struct libmnt_iter
*itr
= NULL
;
1687 struct libmnt_cache
*mpc
= NULL
;
1690 tb
= mnt_new_table_from_file("/proc/self/mountinfo");
1692 fprintf(stderr
, "failed to parse mountinfo\n");
1696 fstab
= create_table(argv
[1], FALSE
);
1700 itr
= mnt_new_iter(MNT_ITER_FORWARD
);
1704 mpc
= mnt_new_cache();
1707 mnt_table_set_cache(tb
, mpc
);
1708 mnt_unref_cache(mpc
);
1710 while(mnt_table_next_fs(fstab
, itr
, &fs
) == 0) {
1711 if (mnt_table_is_fs_mounted(tb
, fs
))
1712 printf("%s already mounted on %s\n",
1713 mnt_fs_get_source(fs
),
1714 mnt_fs_get_target(fs
));
1716 printf("%s not mounted on %s\n",
1717 mnt_fs_get_source(fs
),
1718 mnt_fs_get_target(fs
));
1723 mnt_unref_table(tb
);
1724 mnt_unref_table(fstab
);
1729 /* returns 0 if @a and @b targets are the same */
1730 static int test_uniq_cmp(struct libmnt_table
*tb
__attribute__((__unused__
)),
1731 struct libmnt_fs
*a
,
1732 struct libmnt_fs
*b
)
1737 return mnt_fs_streq_target(a
, mnt_fs_get_target(b
)) ? 0 : 1;
1740 static int test_uniq(struct libmnt_test
*ts
, int argc
, char *argv
[])
1742 struct libmnt_table
*tb
;
1746 fprintf(stderr
, "try --help\n");
1750 tb
= create_table(argv
[1], FALSE
);
1754 if (mnt_table_uniq_fs(tb
, 0, test_uniq_cmp
) == 0) {
1755 struct libmnt_iter
*itr
= mnt_new_iter(MNT_ITER_FORWARD
);
1756 struct libmnt_fs
*fs
;
1759 while (mnt_table_next_fs(tb
, itr
, &fs
) == 0)
1760 mnt_fs_print_debug(fs
, stdout
);
1765 mnt_unref_table(tb
);
1769 int main(int argc
, char *argv
[])
1771 struct libmnt_test tss
[] = {
1772 { "--parse", test_parse
, "<file> [--comments] parse and print tab" },
1773 { "--find-forward", test_find_fw
, "<file> <source|target> <string>" },
1774 { "--find-backward", test_find_bw
, "<file> <source|target> <string>" },
1775 { "--uniq-target", test_uniq
, "<file>" },
1776 { "--find-pair", test_find_pair
, "<file> <source> <target>" },
1777 { "--find-mountpoint", test_find_mountpoint
, "<path>" },
1778 { "--copy-fs", test_copy_fs
, "<file> copy root FS from the file" },
1779 { "--is-mounted", test_is_mounted
, "<fstab> check what from <file> are already mounted" },
1783 return mnt_run_test(tss
, argc
, argv
);
1786 #endif /* TEST_PROGRAM */