]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libmount/src/tab.c
misc: Fix various typos
[thirdparty/util-linux.git] / libmount / 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/**
63de90d4 9 * SECTION: table
0f32f1e2 10 * @title: Table of filesystems
63de90d4 11 * @short_description: container for entries from fstab, mtab or mountinfo
6bd8b7a7 12 *
68164f6c 13 * Note that mnt_table_find_* functions are mount(8) compatible. These functions
d58b3157 14 * try to find an entry in more iterations, where the first attempt is always
192c6aad 15 * based on comparison with unmodified (non-canonicalized or un-evaluated)
d58b3157 16 * paths or tags. For example a fstab with two entries:
3d735589
KZ
17 * <informalexample>
18 * <programlisting>
192c6aad
KZ
19 * LABEL=foo /foo auto rw
20 * /dev/foo /foo auto rw
3d735589
KZ
21 * </programlisting>
22 * </informalexample>
6bd8b7a7 23 *
192c6aad 24 * where both lines are used for the *same* device, then
3d735589
KZ
25 * <informalexample>
26 * <programlisting>
68164f6c 27 * mnt_table_find_source(tb, "/dev/foo", &fs);
3d735589
KZ
28 * </programlisting>
29 * </informalexample>
192c6aad 30 * will returns the second line, and
3d735589
KZ
31 * <informalexample>
32 * <programlisting>
68164f6c 33 * mnt_table_find_source(tb, "LABEL=foo", &fs);
3d735589
KZ
34 * </programlisting>
35 * </informalexample>
192c6aad 36 * will returns the first entry, and
3d735589
KZ
37 * <informalexample>
38 * <programlisting>
68164f6c 39 * mnt_table_find_source(tb, "UUID=anyuuid", &fs);
3d735589
KZ
40 * </programlisting>
41 * </informalexample>
d58b3157 42 * will return the first entry (if UUID matches with the device).
6bd8b7a7 43 */
8e368761 44#include <blkid.h>
6bd8b7a7 45
6bd8b7a7 46#include "mountP.h"
b106d052 47#include "strutils.h"
b2cbe99f 48#include "loopdev.h"
d4eaabc8 49#include "fileutils.h"
cc06a01e 50#include "canonicalize.h"
6bd8b7a7 51
60d29f82 52int is_mountinfo(struct libmnt_table *tb)
51fffa7b
KZ
53{
54 struct libmnt_fs *fs;
55
56 if (!tb)
57 return 0;
58
59 fs = list_first_entry(&tb->ents, struct libmnt_fs, ents);
60 if (fs && mnt_fs_is_kernel(fs) && mnt_fs_get_root(fs))
61 return 1;
62
63 return 0;
64}
65
6bd8b7a7 66/**
68164f6c 67 * mnt_new_table:
6bd8b7a7 68 *
68164f6c 69 * The tab is a container for struct libmnt_fs entries that usually represents a fstab,
6bd8b7a7
KZ
70 * mtab or mountinfo file from your system.
71 *
68164f6c 72 * See also mnt_table_parse_file().
6bd8b7a7 73 *
192c6aad 74 * Returns: newly allocated tab struct.
6bd8b7a7 75 */
68164f6c 76struct libmnt_table *mnt_new_table(void)
6bd8b7a7 77{
68164f6c 78 struct libmnt_table *tb = NULL;
6bd8b7a7 79
68164f6c 80 tb = calloc(1, sizeof(*tb));
6bd8b7a7 81 if (!tb)
9ed7507c
KZ
82 return NULL;
83
83a78332 84 DBG(TAB, ul_debugobj(tb, "alloc"));
c9f1585e 85 tb->refcount = 1;
6bd8b7a7
KZ
86 INIT_LIST_HEAD(&tb->ents);
87 return tb;
6bd8b7a7
KZ
88}
89
90/**
18486fbb 91 * mnt_reset_table:
3d735589 92 * @tb: tab pointer
6bd8b7a7 93 *
26d0c0ae
KZ
94 * Removes all entries (filesystems) from the table. The filesystems with zero
95 * reference count will be deallocated.
18486fbb
KZ
96 *
97 * Returns: 0 on success or negative number in case of error.
6bd8b7a7 98 */
18486fbb 99int mnt_reset_table(struct libmnt_table *tb)
6bd8b7a7
KZ
100{
101 if (!tb)
18486fbb 102 return -EINVAL;
6bd8b7a7 103
83a78332 104 DBG(TAB, ul_debugobj(tb, "reset"));
3f31a959 105
6bd8b7a7 106 while (!list_empty(&tb->ents)) {
68164f6c
KZ
107 struct libmnt_fs *fs = list_entry(tb->ents.next,
108 struct libmnt_fs, ents);
26d0c0ae 109 mnt_table_remove_fs(tb, fs);
6bd8b7a7
KZ
110 }
111
26d0c0ae 112 tb->nents = 0;
18486fbb
KZ
113 return 0;
114}
115
c9f1585e
KZ
116/**
117 * mnt_ref_table:
118 * @tb: table pointer
119 *
120 * Increments reference counter.
121 */
122void mnt_ref_table(struct libmnt_table *tb)
123{
124 if (tb) {
125 tb->refcount++;
83a78332 126 /*DBG(FS, ul_debugobj(tb, "ref=%d", tb->refcount));*/
c9f1585e
KZ
127 }
128}
129
130/**
131 * mnt_unref_table:
132 * @tb: table pointer
133 *
47cca899 134 * De-increments reference counter, on zero the @tb is automatically
c9f1585e
KZ
135 * deallocated by mnt_free_table().
136 */
137void mnt_unref_table(struct libmnt_table *tb)
138{
139 if (tb) {
140 tb->refcount--;
83a78332 141 /*DBG(FS, ul_debugobj(tb, "unref=%d", tb->refcount));*/
c9f1585e
KZ
142 if (tb->refcount <= 0)
143 mnt_free_table(tb);
144 }
145}
146
147
18486fbb
KZ
148/**
149 * mnt_free_table:
150 * @tb: tab pointer
151 *
c9f1585e
KZ
152 * Deallocates the table. This function does not care about reference count. Don't
153 * use this function directly -- it's better to use use mnt_unref_table().
154 *
9e930041 155 * The table entries (filesystems) are unreferenced by mnt_reset_table() and
c9f1585e 156 * cache by mnt_unref_cache().
18486fbb
KZ
157 */
158void mnt_free_table(struct libmnt_table *tb)
159{
160 if (!tb)
161 return;
162
163 mnt_reset_table(tb);
83a78332 164 DBG(TAB, ul_debugobj(tb, "free [refcount=%d]", tb->refcount));
c9f1585e
KZ
165
166 mnt_unref_cache(tb->cache);
cb90e24e
OO
167 free(tb->comm_intro);
168 free(tb->comm_tail);
6bd8b7a7
KZ
169 free(tb);
170}
171
172/**
68164f6c 173 * mnt_table_get_nents:
6bd8b7a7
KZ
174 * @tb: pointer to tab
175 *
26d0c0ae 176 * Returns: number of entries in table.
6bd8b7a7 177 */
68164f6c 178int mnt_table_get_nents(struct libmnt_table *tb)
a2f17bb2 179{
26d0c0ae 180 return tb ? tb->nents : 0;
a2f17bb2
KZ
181}
182
183/**
184 * mnt_table_is_empty:
185 * @tb: pointer to tab
186 *
187 * Returns: 1 if the table is without filesystems, or 0.
188 */
189int mnt_table_is_empty(struct libmnt_table *tb)
6bd8b7a7 190{
a2f17bb2 191 return tb == NULL || list_empty(&tb->ents) ? 1 : 0;
6bd8b7a7
KZ
192}
193
2bc04c11
KZ
194/**
195 * mnt_table_set_userdata:
196 * @tb: pointer to tab
197 * @data: pointer to user data
198 *
199 * Sets pointer to the private user data.
200 *
201 * Returns: 0 on success or negative number in case of error.
202 */
203int mnt_table_set_userdata(struct libmnt_table *tb, void *data)
204{
2bc04c11
KZ
205 if (!tb)
206 return -EINVAL;
207
208 tb->userdata = data;
209 return 0;
210}
211
212/**
213 * mnt_table_get_userdata:
214 * @tb: pointer to tab
215 *
216 * Returns: pointer to user's data.
217 */
218void *mnt_table_get_userdata(struct libmnt_table *tb)
219{
2bc04c11
KZ
220 return tb ? tb->userdata : NULL;
221}
222
cb90e24e
OO
223/**
224 * mnt_table_enable_comments:
225 * @tb: pointer to tab
7b1333fa 226 * @enable: TRUE or FALSE
cb90e24e
OO
227 *
228 * Enables parsing of comments.
229 *
230 * The initial (intro) file comment is accessible by
231 * mnt_table_get_intro_comment(). The intro and the comment of the first fstab
232 * entry has to be separated by blank line. The filesystem comments are
d58b3157 233 * accessible by mnt_fs_get_comment(). The trailing fstab comment is accessible
3035ba93 234 * by mnt_table_get_trailing_comment().
cb90e24e
OO
235 *
236 * <informalexample>
237 * <programlisting>
238 * #
239 * # Intro comment
240 * #
241 *
242 * # this comments belongs to the first fs
243 * LABEL=foo /mnt/foo auto defaults 1 2
244 * # this comments belongs to the second fs
37290a53 245 * LABEL=bar /mnt/bar auto defaults 1 2
cb90e24e
OO
246 * # tailing comment
247 * </programlisting>
248 * </informalexample>
249 */
250void mnt_table_enable_comments(struct libmnt_table *tb, int enable)
251{
cb90e24e
OO
252 if (tb)
253 tb->comms = enable;
254}
255
e670df45
KZ
256/**
257 * mnt_table_with_comments:
258 * @tb: pointer to table
259 *
260 * Returns: 1 if comments parsing is enabled, or 0.
261 */
262int mnt_table_with_comments(struct libmnt_table *tb)
263{
264 assert(tb);
265 return tb ? tb->comms : 0;
266}
267
cb90e24e
OO
268/**
269 * mnt_table_get_intro_comment:
270 * @tb: pointer to tab
271 *
272 * Returns: initial comment in tb
273 */
274const char *mnt_table_get_intro_comment(struct libmnt_table *tb)
275{
cb90e24e
OO
276 return tb ? tb->comm_intro : NULL;
277}
278
279/**
280 * mnt_table_set_into_comment:
281 * @tb: pointer to tab
282 * @comm: comment or NULL
283 *
d58b3157 284 * Sets the initial comment in tb.
cb90e24e
OO
285 *
286 * Returns: 0 on success or negative number in case of error.
287 */
288int mnt_table_set_intro_comment(struct libmnt_table *tb, const char *comm)
289{
deb1c903 290 return strdup_to_struct_member(tb, comm_intro, comm);
cb90e24e
OO
291}
292
293/**
294 * mnt_table_append_into_comment:
295 * @tb: pointer to tab
296 * @comm: comment of NULL
297 *
298 * Appends the initial comment in tb.
299 *
300 * Returns: 0 on success or negative number in case of error.
301 */
302int mnt_table_append_intro_comment(struct libmnt_table *tb, const char *comm)
303{
cb90e24e
OO
304 if (!tb)
305 return -EINVAL;
306 return append_string(&tb->comm_intro, comm);
307}
308
309/**
3035ba93 310 * mnt_table_get_trailing_comment:
cb90e24e
OO
311 * @tb: pointer to tab
312 *
d58b3157 313 * Returns: table trailing comment
cb90e24e 314 */
3035ba93 315const char *mnt_table_get_trailing_comment(struct libmnt_table *tb)
cb90e24e 316{
cb90e24e
OO
317 return tb ? tb->comm_tail : NULL;
318}
319
320/**
3035ba93 321 * mnt_table_set_trailing_comment
cb90e24e 322 * @tb: pointer to tab
7b1333fa 323 * @comm: comment string
cb90e24e 324 *
d58b3157 325 * Sets the trailing comment in table.
cb90e24e
OO
326 *
327 * Returns: 0 on success or negative number in case of error.
328 */
3035ba93 329int mnt_table_set_trailing_comment(struct libmnt_table *tb, const char *comm)
cb90e24e 330{
deb1c903 331 return strdup_to_struct_member(tb, comm_tail, comm);
cb90e24e
OO
332}
333
334/**
3035ba93 335 * mnt_table_append_trailing_comment:
cb90e24e
OO
336 * @tb: pointer to tab
337 * @comm: comment of NULL
338 *
d58b3157 339 * Appends to the trailing table comment.
cb90e24e
OO
340 *
341 * Returns: 0 on success or negative number in case of error.
342 */
3035ba93 343int mnt_table_append_trailing_comment(struct libmnt_table *tb, const char *comm)
cb90e24e 344{
cb90e24e
OO
345 if (!tb)
346 return -EINVAL;
347 return append_string(&tb->comm_tail, comm);
348}
349
6bd8b7a7 350/**
68164f6c 351 * mnt_table_set_cache:
6bd8b7a7 352 * @tb: pointer to tab
68164f6c 353 * @mpc: pointer to struct libmnt_cache instance
6bd8b7a7 354 *
d58b3157 355 * Sets up a cache for canonicalized paths and evaluated tags (LABEL/UUID). The
68164f6c 356 * cache is recommended for mnt_table_find_*() functions.
6bd8b7a7
KZ
357 *
358 * The cache could be shared between more tabs. Be careful when you share the
359 * same cache between more threads -- currently the cache does not provide any
360 * locking method.
361 *
9e930041 362 * This function increments cache reference counter. It's recommended to use
0105691d
KZ
363 * mnt_unref_cache() after mnt_table_set_cache() if you want to keep the cache
364 * referenced by @tb only.
365 *
6bd8b7a7
KZ
366 * See also mnt_new_cache().
367 *
59ae0ddd 368 * Returns: 0 on success or negative number in case of error.
6bd8b7a7 369 */
68164f6c 370int mnt_table_set_cache(struct libmnt_table *tb, struct libmnt_cache *mpc)
6bd8b7a7 371{
6bd8b7a7 372 if (!tb)
59ae0ddd 373 return -EINVAL;
0105691d
KZ
374
375 mnt_ref_cache(mpc); /* new */
376 mnt_unref_cache(tb->cache); /* old */
6bd8b7a7
KZ
377 tb->cache = mpc;
378 return 0;
379}
380
381/**
68164f6c 382 * mnt_table_get_cache:
6bd8b7a7
KZ
383 * @tb: pointer to tab
384 *
68164f6c 385 * Returns: pointer to struct libmnt_cache instance or NULL.
6bd8b7a7 386 */
68164f6c 387struct libmnt_cache *mnt_table_get_cache(struct libmnt_table *tb)
6bd8b7a7 388{
6bd8b7a7
KZ
389 return tb ? tb->cache : NULL;
390}
391
6bd8b7a7 392/**
68164f6c 393 * mnt_table_add_fs:
6bd8b7a7
KZ
394 * @tb: tab pointer
395 * @fs: new entry
396 *
26d0c0ae
KZ
397 * Adds a new entry to tab and increment @fs reference counter. Don't forget to
398 * use mnt_unref_fs() after mnt_table_add_fs() you want to keep the @fs
399 * referenced by the table only.
6bd8b7a7 400 *
59ae0ddd 401 * Returns: 0 on success or negative number in case of error.
6bd8b7a7 402 */
68164f6c 403int mnt_table_add_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
6bd8b7a7 404{
6bd8b7a7 405 if (!tb || !fs)
59ae0ddd 406 return -EINVAL;
6bd8b7a7 407
26d0c0ae 408 mnt_ref_fs(fs);
6bd8b7a7 409 list_add_tail(&fs->ents, &tb->ents);
26d0c0ae 410 tb->nents++;
6bd8b7a7 411
83a78332 412 DBG(TAB, ul_debugobj(tb, "add entry: %s %s",
3f31a959 413 mnt_fs_get_source(fs), mnt_fs_get_target(fs)));
6bd8b7a7
KZ
414 return 0;
415}
416
417/**
68164f6c 418 * mnt_table_remove_fs:
6bd8b7a7
KZ
419 * @tb: tab pointer
420 * @fs: new entry
421 *
26d0c0ae
KZ
422 * Removes the @fs from the table and de-increment reference counter of the @fs. The
423 * filesystem with zero reference counter will be deallocated. Don't forget to use
424 * mnt_ref_fs() before call mnt_table_remove_fs() if you want to use @fs later.
425 *
59ae0ddd 426 * Returns: 0 on success or negative number in case of error.
6bd8b7a7 427 */
68164f6c 428int mnt_table_remove_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
6bd8b7a7 429{
6bd8b7a7 430 if (!tb || !fs)
59ae0ddd 431 return -EINVAL;
14104e93 432
6bd8b7a7 433 list_del(&fs->ents);
14104e93
KZ
434 INIT_LIST_HEAD(&fs->ents); /* otherwise FS still points to the list */
435
26d0c0ae
KZ
436 mnt_unref_fs(fs);
437 tb->nents--;
6bd8b7a7
KZ
438 return 0;
439}
440
26b4f9e4 441/**
68164f6c 442 * mnt_table_get_root_fs:
26b4f9e4
KZ
443 * @tb: mountinfo file (/proc/self/mountinfo)
444 * @root: returns pointer to the root filesystem (/)
445 *
d58b3157 446 * The function uses the parent ID from the mountinfo file to determine the root filesystem
c667aff9 447 * (the filesystem with the smallest ID). The function is designed mostly for
d58b3157 448 * applications where it is necessary to sort mountpoints by IDs to get the tree
c667aff9
KZ
449 * of the mountpoints (e.g. findmnt default output).
450 *
d58b3157 451 * If you're not sure, then use
c667aff9
KZ
452 *
453 * mnt_table_find_target(tb, "/", MNT_ITER_BACKWARD);
454 *
d58b3157 455 * this is more robust and usable for arbitrary tab files (including fstab).
c667aff9 456 *
d58b3157 457 * Returns: 0 on success or negative number in case of error.
26b4f9e4 458 */
68164f6c 459int mnt_table_get_root_fs(struct libmnt_table *tb, struct libmnt_fs **root)
26b4f9e4 460{
68164f6c
KZ
461 struct libmnt_iter itr;
462 struct libmnt_fs *fs;
26b4f9e4
KZ
463 int root_id = 0;
464
6c373810 465 if (!tb || !root || !is_mountinfo(tb))
59ae0ddd 466 return -EINVAL;
26b4f9e4 467
83a78332 468 DBG(TAB, ul_debugobj(tb, "lookup root fs"));
20aae9d3 469
2e358a90
TB
470 *root = NULL;
471
26b4f9e4 472 mnt_reset_iter(&itr, MNT_ITER_FORWARD);
68164f6c 473 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
26b4f9e4 474 int id = mnt_fs_get_parent_id(fs);
26b4f9e4
KZ
475
476 if (!*root || id < root_id) {
477 *root = fs;
478 root_id = id;
479 }
480 }
481
6c373810 482 return *root ? 0 : -EINVAL;
26b4f9e4
KZ
483}
484
485/**
68164f6c 486 * mnt_table_next_child_fs:
26b4f9e4 487 * @tb: mountinfo file (/proc/self/mountinfo)
3d735589 488 * @itr: iterator
26b4f9e4
KZ
489 * @parent: parental FS
490 * @chld: returns the next child filesystem
491 *
d58b3157 492 * Note that filesystems are returned in the order of mounting (according to
26b4f9e4
KZ
493 * IDs in /proc/self/mountinfo).
494 *
d58b3157 495 * Returns: 0 on success, negative number in case of error or 1 at the end of list.
26b4f9e4 496 */
68164f6c
KZ
497int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
498 struct libmnt_fs *parent, struct libmnt_fs **chld)
26b4f9e4 499{
68164f6c 500 struct libmnt_fs *fs;
26b4f9e4
KZ
501 int parent_id, lastchld_id = 0, chld_id = 0;
502
6c373810 503 if (!tb || !itr || !parent || !is_mountinfo(tb))
59ae0ddd 504 return -EINVAL;
26b4f9e4 505
83a78332 506 DBG(TAB, ul_debugobj(tb, "lookup next child of '%s'",
3f31a959 507 mnt_fs_get_target(parent)));
20aae9d3 508
26b4f9e4 509 parent_id = mnt_fs_get_id(parent);
26b4f9e4
KZ
510
511 /* get ID of the previously returned child */
512 if (itr->head && itr->p != itr->head) {
68164f6c 513 MNT_ITER_ITERATE(itr, fs, struct libmnt_fs, ents);
26b4f9e4
KZ
514 lastchld_id = mnt_fs_get_id(fs);
515 }
516
517 *chld = NULL;
518
519 mnt_reset_iter(itr, MNT_ITER_FORWARD);
68164f6c 520 while(mnt_table_next_fs(tb, itr, &fs) == 0) {
26b4f9e4
KZ
521 int id;
522
523 if (mnt_fs_get_parent_id(fs) != parent_id)
524 continue;
525
526 id = mnt_fs_get_id(fs);
527
d58b3157 528 /* avoid an infinite loop. This only happens in rare cases
bf91904c
DR
529 * such as in early userspace when the rootfs is its own parent */
530 if (id == parent_id)
531 continue;
532
26b4f9e4
KZ
533 if ((!lastchld_id || id > lastchld_id) &&
534 (!*chld || id < chld_id)) {
535 *chld = fs;
536 chld_id = id;
537 }
538 }
539
6c373810 540 if (!*chld)
26b4f9e4
KZ
541 return 1; /* end of iterator */
542
543 /* set the iterator to the @chld for the next call */
68164f6c 544 mnt_table_set_iter(tb, itr, *chld);
26b4f9e4
KZ
545
546 return 0;
547}
548
6bd8b7a7 549/**
68164f6c 550 * mnt_table_next_fs:
6bd8b7a7
KZ
551 * @tb: tab pointer
552 * @itr: iterator
553 * @fs: returns the next tab entry
554 *
d58b3157 555 * Returns: 0 on success, negative number in case of error or 1 at the end of list.
6bd8b7a7 556 *
0f32f1e2 557 * Example:
3d735589
KZ
558 * <informalexample>
559 * <programlisting>
68164f6c 560 * while(mnt_table_next_fs(tb, itr, &fs) == 0) {
6bd8b7a7
KZ
561 * const char *dir = mnt_fs_get_target(fs);
562 * printf("mount point: %s\n", dir);
563 * }
3d735589
KZ
564 * </programlisting>
565 * </informalexample>
0f32f1e2 566 *
d58b3157 567 * lists all mountpoints from fstab in reverse order.
6bd8b7a7 568 */
68164f6c 569int mnt_table_next_fs(struct libmnt_table *tb, struct libmnt_iter *itr, struct libmnt_fs **fs)
6bd8b7a7 570{
59ae0ddd 571 int rc = 1;
3fca8422 572
6bd8b7a7 573 if (!tb || !itr || !fs)
59ae0ddd 574 return -EINVAL;
0532ba1d
KZ
575 *fs = NULL;
576
6bd8b7a7
KZ
577 if (!itr->head)
578 MNT_ITER_INIT(itr, &tb->ents);
579 if (itr->p != itr->head) {
68164f6c 580 MNT_ITER_ITERATE(itr, *fs, struct libmnt_fs, ents);
3fca8422 581 rc = 0;
6bd8b7a7
KZ
582 }
583
3fca8422
KZ
584 return rc;
585}
586
686a6467
KZ
587/**
588 * mnt_table_first_fs:
589 * @tb: tab pointer
590 * @fs: returns the first tab entry
591 *
592 * Returns: 0 on success, negative number in case of error or 1 at the end of list.
593 */
594int mnt_table_first_fs(struct libmnt_table *tb, struct libmnt_fs **fs)
595{
686a6467
KZ
596 if (!tb || !fs)
597 return -EINVAL;
598 if (list_empty(&tb->ents))
599 return 1;
600 *fs = list_first_entry(&tb->ents, struct libmnt_fs, ents);
601 return 0;
602}
603
604/**
605 * mnt_table_last_fs:
606 * @tb: tab pointer
607 * @fs: returns the last tab entry
608 *
609 * Returns: 0 on success, negative number in case of error or 1 at the end of list.
610 */
611int mnt_table_last_fs(struct libmnt_table *tb, struct libmnt_fs **fs)
612{
686a6467
KZ
613 if (!tb || !fs)
614 return -EINVAL;
615 if (list_empty(&tb->ents))
616 return 1;
617 *fs = list_last_entry(&tb->ents, struct libmnt_fs, ents);
618 return 0;
619}
620
3fca8422 621/**
68164f6c 622 * mnt_table_find_next_fs:
3fca8422
KZ
623 * @tb: table
624 * @itr: iterator
d58b3157 625 * @match_func: function returning 1 or 0
3d735589 626 * @userdata: extra data for match_func
3fca8422
KZ
627 * @fs: returns pointer to the next matching table entry
628 *
d58b3157 629 * This function allows searching in @tb.
3fca8422 630 *
59ae0ddd 631 * Returns: negative number in case of error, 1 at end of table or 0 o success.
3fca8422 632 */
68164f6c
KZ
633int mnt_table_find_next_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
634 int (*match_func)(struct libmnt_fs *, void *), void *userdata,
635 struct libmnt_fs **fs)
3fca8422
KZ
636{
637 if (!tb || !itr || !fs || !match_func)
59ae0ddd 638 return -EINVAL;
3fca8422 639
83a78332 640 DBG(TAB, ul_debugobj(tb, "lookup next fs"));
20aae9d3 641
3fca8422
KZ
642 if (!itr->head)
643 MNT_ITER_INIT(itr, &tb->ents);
644
645 do {
646 if (itr->p != itr->head)
68164f6c 647 MNT_ITER_ITERATE(itr, *fs, struct libmnt_fs, ents);
3fca8422
KZ
648 else
649 break; /* end */
650
3fca8422
KZ
651 if (match_func(*fs, userdata))
652 return 0;
653 } while(1);
654
26b4f9e4 655 *fs = NULL;
6bd8b7a7
KZ
656 return 1;
657}
658
51fffa7b
KZ
659static int mnt_table_move_parent(struct libmnt_table *tb, int oldid, int newid)
660{
661 struct libmnt_iter itr;
662 struct libmnt_fs *fs;
663
51fffa7b
KZ
664 if (!tb)
665 return -EINVAL;
666 if (list_empty(&tb->ents))
667 return 0;
668
83a78332 669 DBG(TAB, ul_debugobj(tb, "moving parent ID from %d -> %d", oldid, newid));
51fffa7b
KZ
670 mnt_reset_iter(&itr, MNT_ITER_FORWARD);
671
672 while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
673 if (fs->parent == oldid)
674 fs->parent = newid;
675 }
676 return 0;
677}
678
679/**
680 * mnt_table_uniq_fs:
681 * @tb: table
cbe92027 682 * @flags: MNT_UNIQ_*
51fffa7b
KZ
683 * @cmp: function to compare filesystems
684 *
685 * This function de-duplicate the @tb, but does not change order of the
686 * filesystems. The @cmp function has to return 0 if the filesystems are
687 * equal, otherwise non-zero.
688 *
689 * The default is to keep in the table later mounted filesystems (function uses
690 * backward mode iterator).
691 *
692 * @MNT_UNIQ_FORWARD: remove later mounted filesystems
9e930041 693 * @MNT_UNIQ_KEEPTREE: keep parent->id relationship still valid
51fffa7b
KZ
694 *
695 * Returns: negative number in case of error, or 0 o success.
696 */
697int mnt_table_uniq_fs(struct libmnt_table *tb, int flags,
698 int (*cmp)(struct libmnt_table *,
699 struct libmnt_fs *,
700 struct libmnt_fs *))
701{
702 struct libmnt_iter itr;
703 struct libmnt_fs *fs;
704 int direction = MNT_ITER_BACKWARD;
705
51fffa7b
KZ
706 if (!tb || !cmp)
707 return -EINVAL;
708 if (list_empty(&tb->ents))
709 return 0;
710
711 if (flags & MNT_UNIQ_FORWARD)
712 direction = MNT_ITER_FORWARD;
713
83a78332 714 DBG(TAB, ul_debugobj(tb, "de-duplicate"));
51fffa7b
KZ
715 mnt_reset_iter(&itr, direction);
716
717 if ((flags & MNT_UNIQ_KEEPTREE) && !is_mountinfo(tb))
718 flags &= ~MNT_UNIQ_KEEPTREE;
719
720 while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
721 int want = 1;
722 struct libmnt_iter xtr;
723 struct libmnt_fs *x;
724
725 mnt_reset_iter(&xtr, direction);
726 while (want && mnt_table_next_fs(tb, &xtr, &x) == 0) {
727 if (fs == x)
728 break;
729 want = cmp(tb, x, fs) != 0;
730 }
731
732 if (!want) {
733 if (flags & MNT_UNIQ_KEEPTREE)
734 mnt_table_move_parent(tb, mnt_fs_get_id(fs),
735 mnt_fs_get_parent_id(fs));
736
83a78332 737 DBG(TAB, ul_debugobj(tb, "remove duplicate %s",
51fffa7b
KZ
738 mnt_fs_get_target(fs)));
739 mnt_table_remove_fs(tb, fs);
740 }
741 }
742
743 return 0;
744}
745
6bd8b7a7 746/**
68164f6c 747 * mnt_table_set_iter:
6bd8b7a7
KZ
748 * @tb: tab pointer
749 * @itr: iterator
750 * @fs: tab entry
751 *
752 * Sets @iter to the position of @fs in the file @tb.
753 *
59ae0ddd 754 * Returns: 0 on success, negative number in case of error.
6bd8b7a7 755 */
68164f6c 756int mnt_table_set_iter(struct libmnt_table *tb, struct libmnt_iter *itr, struct libmnt_fs *fs)
6bd8b7a7 757{
6bd8b7a7 758 if (!tb || !itr || !fs)
59ae0ddd 759 return -EINVAL;
6bd8b7a7
KZ
760
761 MNT_ITER_INIT(itr, &tb->ents);
762 itr->p = &fs->ents;
763
764 return 0;
765}
766
dcc15ce5
KZ
767/**
768 * mnt_table_find_mountpoint:
769 * @tb: tab pointer
770 * @path: directory
771 * @direction: MNT_ITER_{FORWARD,BACKWARD}
772 *
d58b3157 773 * Same as mnt_get_mountpoint(), except this function does not rely on
dcc15ce5
KZ
774 * st_dev numbers.
775 *
776 * Returns: a tab entry or NULL.
777 */
778struct libmnt_fs *mnt_table_find_mountpoint(struct libmnt_table *tb,
779 const char *path,
780 int direction)
781{
782 char *mnt;
783
7ba207e7 784 if (!tb || !path || !*path)
dcc15ce5 785 return NULL;
4cd271ad
KZ
786 if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
787 return NULL;
dcc15ce5 788
83a78332 789 DBG(TAB, ul_debugobj(tb, "lookup MOUNTPOINT: '%s'", path));
dcc15ce5
KZ
790
791 mnt = strdup(path);
792 if (!mnt)
793 return NULL;
794
795 do {
796 char *p;
797 struct libmnt_fs *fs;
798
799 fs = mnt_table_find_target(tb, mnt, direction);
800 if (fs) {
801 free(mnt);
802 return fs;
803 }
804
805 p = stripoff_last_component(mnt);
41510d26 806 if (!p)
dcc15ce5
KZ
807 break;
808 } while (mnt && *(mnt + 1) != '\0');
809
810 free(mnt);
811 return mnt_table_find_target(tb, "/", direction);
812}
813
6bd8b7a7 814/**
68164f6c 815 * mnt_table_find_target:
6bd8b7a7
KZ
816 * @tb: tab pointer
817 * @path: mountpoint directory
818 * @direction: MNT_ITER_{FORWARD,BACKWARD}
819 *
d58b3157
OO
820 * Try to lookup an entry in the given tab, three iterations are possible, the first
821 * with @path, the second with realpath(@path) and the third with realpath(@path)
0382ba32
ER
822 * against realpath(fs->target). The 2nd and 3rd iterations are not performed when
823 * the @tb cache is not set (see mnt_table_set_cache()). If
824 * mnt_cache_set_targets(cache, mtab) was called, the 3rd iteration skips any
825 * @fs->target found in @mtab (see mnt_resolve_target()).
6bd8b7a7 826 *
192c6aad 827 * Returns: a tab entry or NULL.
6bd8b7a7 828 */
68164f6c 829struct libmnt_fs *mnt_table_find_target(struct libmnt_table *tb, const char *path, int direction)
6bd8b7a7 830{
68164f6c
KZ
831 struct libmnt_iter itr;
832 struct libmnt_fs *fs = NULL;
6bd8b7a7
KZ
833 char *cn;
834
7ba207e7 835 if (!tb || !path || !*path)
59ae0ddd 836 return NULL;
4cd271ad
KZ
837 if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
838 return NULL;
59ae0ddd 839
83a78332 840 DBG(TAB, ul_debugobj(tb, "lookup TARGET: '%s'", path));
6bd8b7a7
KZ
841
842 /* native @target */
843 mnt_reset_iter(&itr, direction);
de60d08e 844 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
6699e742 845 if (mnt_fs_streq_target(fs, path))
6bd8b7a7 846 return fs;
de60d08e 847 }
2238214d
KZ
848
849 /* try absolute path */
850 if (is_relative_path(path) && (cn = absolute_path(path))) {
851 DBG(TAB, ul_debugobj(tb, "lookup absolute TARGET: '%s'", cn));
852 mnt_reset_iter(&itr, direction);
853 while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
854 if (mnt_fs_streq_target(fs, cn)) {
855 free(cn);
856 return fs;
857 }
858 }
859 free(cn);
860 }
861
6bd8b7a7
KZ
862 if (!tb->cache || !(cn = mnt_resolve_path(path, tb->cache)))
863 return NULL;
864
83a78332 865 DBG(TAB, ul_debugobj(tb, "lookup canonical TARGET: '%s'", cn));
7ba207e7 866
68164f6c 867 /* canonicalized paths in struct libmnt_table */
6bd8b7a7 868 mnt_reset_iter(&itr, direction);
68164f6c 869 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
6699e742 870 if (mnt_fs_streq_target(fs, cn))
6bd8b7a7
KZ
871 return fs;
872 }
873
9e930041 874 /* non-canonical path in struct libmnt_table
fa705b54 875 * -- note that mountpoint in /proc/self/mountinfo is already
d58b3157 876 * canonicalized by the kernel
fa705b54 877 */
6bd8b7a7 878 mnt_reset_iter(&itr, direction);
68164f6c 879 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
6bd8b7a7 880 char *p;
9dd75aa6 881
fa705b54
KZ
882 if (!fs->target
883 || mnt_fs_is_swaparea(fs)
884 || mnt_fs_is_kernel(fs)
885 || (*fs->target == '/' && *(fs->target + 1) == '\0'))
6bd8b7a7 886 continue;
9dd75aa6 887
0382ba32 888 p = mnt_resolve_target(fs->target, tb->cache);
6699e742
KZ
889 /* both canonicalized, strcmp() is fine here */
890 if (p && strcmp(cn, p) == 0)
6bd8b7a7
KZ
891 return fs;
892 }
893 return NULL;
894}
895
896/**
68164f6c 897 * mnt_table_find_srcpath:
6bd8b7a7 898 * @tb: tab pointer
f12aac6e 899 * @path: source path (devname or dirname) or NULL
6bd8b7a7
KZ
900 * @direction: MNT_ITER_{FORWARD,BACKWARD}
901 *
d58b3157
OO
902 * Try to lookup an entry in the given tab, four iterations are possible, the first
903 * with @path, the second with realpath(@path), the third with tags (LABEL, UUID, ..)
904 * from @path and the fourth with realpath(@path) against realpath(entry->srcpath).
6bd8b7a7 905 *
d58b3157 906 * The 2nd, 3rd and 4th iterations are not performed when the @tb cache is not
68164f6c 907 * set (see mnt_table_set_cache()).
6bd8b7a7 908 *
d0ce7c07
DR
909 * Note that NULL is a valid source path; it will be replaced with "none". The
910 * "none" is used in /proc/{mounts,self/mountinfo} for pseudo filesystems.
f12aac6e 911 *
192c6aad 912 * Returns: a tab entry or NULL.
6bd8b7a7 913 */
68164f6c 914struct libmnt_fs *mnt_table_find_srcpath(struct libmnt_table *tb, const char *path, int direction)
6bd8b7a7 915{
68164f6c
KZ
916 struct libmnt_iter itr;
917 struct libmnt_fs *fs = NULL;
a2f17bb2 918 int ntags = 0, nents;
6bd8b7a7
KZ
919 char *cn;
920 const char *p;
921
7ba207e7 922 if (!tb || !path || !*path)
dcc15ce5 923 return NULL;
4cd271ad
KZ
924 if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
925 return NULL;
6bd8b7a7 926
83a78332 927 DBG(TAB, ul_debugobj(tb, "lookup SRCPATH: '%s'", path));
6bd8b7a7
KZ
928
929 /* native paths */
930 mnt_reset_iter(&itr, direction);
68164f6c 931 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
ab8c6e05 932 if (mnt_fs_streq_srcpath(fs, path))
6bd8b7a7 933 return fs;
ab8c6e05
KZ
934 if (mnt_fs_get_tag(fs, NULL, NULL) == 0)
935 ntags++;
6bd8b7a7
KZ
936 }
937
f12aac6e 938 if (!path || !tb->cache || !(cn = mnt_resolve_path(path, tb->cache)))
6bd8b7a7
KZ
939 return NULL;
940
83a78332 941 DBG(TAB, ul_debugobj(tb, "lookup canonical SRCPATH: '%s'", cn));
7ba207e7 942
a2f17bb2
KZ
943 nents = mnt_table_get_nents(tb);
944
68164f6c 945 /* canonicalized paths in struct libmnt_table */
a2f17bb2 946 if (ntags < nents) {
6bd8b7a7 947 mnt_reset_iter(&itr, direction);
68164f6c 948 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
ab8c6e05 949 if (mnt_fs_streq_srcpath(fs, cn))
6bd8b7a7
KZ
950 return fs;
951 }
952 }
953
954 /* evaluated tag */
3fca8422 955 if (ntags) {
ba7232a1
KZ
956 int rc = mnt_cache_read_tags(tb->cache, cn);
957
6bd8b7a7 958 mnt_reset_iter(&itr, direction);
6bd8b7a7 959
ba7232a1 960 if (rc == 0) {
3fca8422 961 /* @path's TAGs are in the cache */
68164f6c 962 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
3fca8422 963 const char *t, *v;
6bd8b7a7 964
3fca8422
KZ
965 if (mnt_fs_get_tag(fs, &t, &v))
966 continue;
967
968 if (mnt_cache_device_has_tag(tb->cache, cn, t, v))
969 return fs;
970 }
ba7232a1 971 } else if (rc < 0 && errno == EACCES) {
d58b3157 972 /* @path is inaccessible, try evaluating all TAGs in @tb
3fca8422 973 * by udev symlinks -- this could be expensive on systems
d58b3157 974 * with a huge fstab/mtab */
68164f6c 975 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
3fca8422
KZ
976 const char *t, *v, *x;
977 if (mnt_fs_get_tag(fs, &t, &v))
978 continue;
979 x = mnt_resolve_tag(t, v, tb->cache);
6699e742
KZ
980
981 /* both canonicalized, strcmp() is fine here */
982 if (x && strcmp(x, cn) == 0)
3fca8422
KZ
983 return fs;
984 }
6bd8b7a7
KZ
985 }
986 }
987
68164f6c 988 /* non-canonicalized paths in struct libmnt_table */
a2f17bb2 989 if (ntags <= nents) {
6bd8b7a7 990 mnt_reset_iter(&itr, direction);
68164f6c 991 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
c70d9d76 992 if (mnt_fs_is_netfs(fs) || mnt_fs_is_pseudofs(fs))
9dd75aa6 993 continue;
6bd8b7a7
KZ
994 p = mnt_fs_get_srcpath(fs);
995 if (p)
996 p = mnt_resolve_path(p, tb->cache);
6699e742
KZ
997
998 /* both canonicalized, strcmp() is fine here */
999 if (p && strcmp(p, cn) == 0)
6bd8b7a7
KZ
1000 return fs;
1001 }
1002 }
1003
1004 return NULL;
1005}
1006
1007
1008/**
68164f6c 1009 * mnt_table_find_tag:
6bd8b7a7
KZ
1010 * @tb: tab pointer
1011 * @tag: tag name (e.g "LABEL", "UUID", ...)
1012 * @val: tag value
1013 * @direction: MNT_ITER_{FORWARD,BACKWARD}
1014 *
d58b3157 1015 * Try to lookup an entry in the given tab, the first attempt is to lookup by @tag and
6bd8b7a7 1016 * @val, for the second attempt the tag is evaluated (converted to the device
d58b3157 1017 * name) and mnt_table_find_srcpath() is performed. The second attempt is not
68164f6c 1018 * performed when @tb cache is not set (see mnt_table_set_cache()).
6bd8b7a7 1019
192c6aad 1020 * Returns: a tab entry or NULL.
6bd8b7a7 1021 */
68164f6c 1022struct libmnt_fs *mnt_table_find_tag(struct libmnt_table *tb, const char *tag,
6bd8b7a7
KZ
1023 const char *val, int direction)
1024{
68164f6c
KZ
1025 struct libmnt_iter itr;
1026 struct libmnt_fs *fs = NULL;
6bd8b7a7 1027
7ba207e7 1028 if (!tb || !tag || !*tag || !val)
6bd8b7a7 1029 return NULL;
4cd271ad
KZ
1030 if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
1031 return NULL;
6bd8b7a7 1032
83a78332 1033 DBG(TAB, ul_debugobj(tb, "lookup by TAG: %s %s", tag, val));
6bd8b7a7
KZ
1034
1035 /* look up by TAG */
1036 mnt_reset_iter(&itr, direction);
68164f6c 1037 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
6bd8b7a7
KZ
1038 if (fs->tagname && fs->tagval &&
1039 strcmp(fs->tagname, tag) == 0 &&
1040 strcmp(fs->tagval, val) == 0)
1041 return fs;
1042 }
1043
1044 if (tb->cache) {
1045 /* look up by device name */
1046 char *cn = mnt_resolve_tag(tag, val, tb->cache);
1047 if (cn)
68164f6c 1048 return mnt_table_find_srcpath(tb, cn, direction);
6bd8b7a7
KZ
1049 }
1050 return NULL;
1051}
1052
2cd28fc8
SB
1053/**
1054 * mnt_table_find_target_with_option:
1055 * @tb: tab pointer
1056 * @path: mountpoint directory
1057 * @option: option name (e.g "subvol", "subvolid", ...)
1058 * @val: option value or NULL
1059 * @direction: MNT_ITER_{FORWARD,BACKWARD}
1060 *
1061 * Try to lookup an entry in the given tab that matches combination of @path
1062 * and @option. In difference to mnt_table_find_target(), only @path iteration
1063 * is done. No lookup by device name, no canonicalization.
1064 *
1065 * Returns: a tab entry or NULL.
1066 *
1067 * Since: 2.28
1068 */
1069struct libmnt_fs *mnt_table_find_target_with_option(
1070 struct libmnt_table *tb, const char *path,
1071 const char *option, const char *val, int direction)
1072{
1073 struct libmnt_iter itr;
1074 struct libmnt_fs *fs = NULL;
1075 char *optval = NULL;
1076 size_t optvalsz = 0, valsz = val ? strlen(val) : 0;
1077
1078 if (!tb || !path || !*path || !option || !*option || !val)
1079 return NULL;
1080 if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
1081 return NULL;
1082
1083 DBG(TAB, ul_debugobj(tb, "lookup TARGET: '%s' with OPTION %s %s", path, option, val));
1084
1085 /* look up by native @target with OPTION */
1086 mnt_reset_iter(&itr, direction);
1087 while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
1088 if (mnt_fs_streq_target(fs, path)
1089 && mnt_fs_get_option(fs, option, &optval, &optvalsz) == 0
1090 && (!val || (optvalsz == valsz
1091 && strncmp(optval, val, optvalsz) == 0)))
1092 return fs;
1093 }
1094 return NULL;
1095}
1096
6bd8b7a7 1097/**
68164f6c 1098 * mnt_table_find_source:
6bd8b7a7
KZ
1099 * @tb: tab pointer
1100 * @source: TAG or path
3d735589 1101 * @direction: MNT_ITER_{FORWARD,BACKWARD}
6bd8b7a7 1102 *
d58b3157
OO
1103 * This is a high-level API for mnt_table_find_{srcpath,tag}. You needn't care
1104 * about the @source format (device, LABEL, UUID, ...). This function parses
1105 * the @source and calls mnt_table_find_tag() or mnt_table_find_srcpath().
6bd8b7a7 1106 *
192c6aad 1107 * Returns: a tab entry or NULL.
6bd8b7a7 1108 */
f12aac6e
KZ
1109struct libmnt_fs *mnt_table_find_source(struct libmnt_table *tb,
1110 const char *source, int direction)
6bd8b7a7 1111{
2c6b25f0
KZ
1112 struct libmnt_fs *fs;
1113 char *t = NULL, *v = NULL;
6bd8b7a7 1114
f12aac6e 1115 if (!tb)
6bd8b7a7 1116 return NULL;
4cd271ad
KZ
1117 if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
1118 return NULL;
6bd8b7a7 1119
83a78332 1120 DBG(TAB, ul_debugobj(tb, "lookup SOURCE: '%s'", source));
6bd8b7a7 1121
2c6b25f0 1122 if (blkid_parse_tag_string(source, &t, &v) || !mnt_valid_tagname(t))
68164f6c 1123 fs = mnt_table_find_srcpath(tb, source, direction);
2c6b25f0
KZ
1124 else
1125 fs = mnt_table_find_tag(tb, t, v, direction);
1126
1127 free(t);
1128 free(v);
6bd8b7a7
KZ
1129
1130 return fs;
1131}
1132
059c696f 1133/**
68164f6c 1134 * mnt_table_find_pair
059c696f
KZ
1135 * @tb: tab pointer
1136 * @source: TAG or path
1137 * @target: mountpoint
1138 * @direction: MNT_ITER_{FORWARD,BACKWARD}
1139 *
1140 * This function is implemented by mnt_fs_match_source() and
d58b3157 1141 * mnt_fs_match_target() functions. It means that this is more expensive than
68164f6c 1142 * others mnt_table_find_* function, because every @tab entry is fully evaluated.
059c696f
KZ
1143 *
1144 * Returns: a tab entry or NULL.
1145 */
68164f6c 1146struct libmnt_fs *mnt_table_find_pair(struct libmnt_table *tb, const char *source,
f12aac6e 1147 const char *target, int direction)
059c696f 1148{
68164f6c
KZ
1149 struct libmnt_fs *fs = NULL;
1150 struct libmnt_iter itr;
059c696f 1151
7ba207e7 1152 if (!tb || !target || !*target || !source || !*source)
059c696f 1153 return NULL;
4cd271ad
KZ
1154 if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
1155 return NULL;
059c696f 1156
83a78332 1157 DBG(TAB, ul_debugobj(tb, "lookup SOURCE: %s TARGET: %s", source, target));
059c696f
KZ
1158
1159 mnt_reset_iter(&itr, direction);
68164f6c 1160 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
059c696f
KZ
1161
1162 if (mnt_fs_match_target(fs, target, tb->cache) &&
1163 mnt_fs_match_source(fs, source, tb->cache))
1164 return fs;
1165 }
1166
1167 return NULL;
1168}
1169
677ff053
KZ
1170/**
1171 * mnt_table_find_devno
1172 * @tb: /proc/self/mountinfo
1173 * @devno: device number
1174 * @direction: MNT_ITER_{FORWARD,BACKWARD}
1175 *
d58b3157 1176 * Note that zero could be a valid device number for the root pseudo filesystem (e.g.
677ff053
KZ
1177 * tmpfs).
1178 *
1179 * Returns: a tab entry or NULL.
1180 */
1181struct libmnt_fs *mnt_table_find_devno(struct libmnt_table *tb,
1182 dev_t devno, int direction)
1183{
1184 struct libmnt_fs *fs = NULL;
1185 struct libmnt_iter itr;
1186
677ff053
KZ
1187 if (!tb)
1188 return NULL;
4cd271ad
KZ
1189 if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
1190 return NULL;
677ff053 1191
83a78332 1192 DBG(TAB, ul_debugobj(tb, "lookup DEVNO: %d", (int) devno));
677ff053
KZ
1193
1194 mnt_reset_iter(&itr, direction);
1195
1196 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
1197 if (mnt_fs_get_devno(fs) == devno)
1198 return fs;
1199 }
1200
1201 return NULL;
1202}
1203
cc06a01e
KZ
1204static char *remove_mountpoint_from_path(const char *path, const char *mnt)
1205{
1206 char *res;
1207 const char *p;
1208 size_t sz;
1209
1210 sz = strlen(mnt);
1211 p = sz > 1 ? path + sz : path;
1212
1213 res = *p ? strdup(p) : strdup("/");
1214 DBG(UTILS, ul_debug("%s fs-root is %s", path, res));
1215 return res;
1216}
1217
9aa3173b
KZ
1218#ifdef HAVE_BTRFS_SUPPORT
1219static int get_btrfs_fs_root(struct libmnt_table *tb, struct libmnt_fs *fs, char **root)
1220{
1221 char *vol = NULL, *p;
1222 size_t sz, volsz = 0;
1223
1224 DBG(BTRFS, ul_debug("lookup for btrfs FS root"));
1225 *root = NULL;
1226
1227 if (mnt_fs_get_option(fs, "subvolid", &vol, &volsz) == 0) {
1228 char *target;
1229 struct libmnt_fs *f;
1230 char subvolidstr[sizeof(stringify_value(UINT64_MAX))];
1231
1232 DBG(BTRFS, ul_debug(" found subvolid=%s, checking", vol));
1233
1234 assert (volsz + 1 < sizeof(stringify_value(UINT64_MAX)));
1235 memcpy(subvolidstr, vol, volsz);
1236 subvolidstr[volsz] = '\0';
1237
1238 target = mnt_resolve_target(mnt_fs_get_target(fs), tb->cache);
1239 if (!target)
1240 goto err;
1241
c59409b9 1242 DBG(BTRFS, ul_debug(" trying target=%s subvolid=%s", target, subvolidstr));
9aa3173b
KZ
1243 f = mnt_table_find_target_with_option(tb, target,
1244 "subvolid", subvolidstr,
1245 MNT_ITER_BACKWARD);
1246 if (!tb->cache)
1247 free(target);
1248 if (!f)
1249 goto not_found;
1250
1251 /* Instead of set of BACKREF queries constructing subvol path
1252 * corresponding to a particular subvolid, use the one in
1253 * mountinfo. Kernel keeps subvol path up to date.
1254 */
1255 if (mnt_fs_get_option(f, "subvol", &vol, &volsz) != 0)
1256 goto not_found;
1257
1258 } else if (mnt_fs_get_option(fs, "subvol", &vol, &volsz) != 0) {
1259 /* If fstab entry does not contain "subvol", we have to
1260 * check, whether btrfs has default subvolume defined.
1261 */
1262 uint64_t default_id;
1263 char *target;
1264 struct libmnt_fs *f;
1265 char default_id_str[sizeof(stringify_value(UINT64_MAX))];
1266
1267 DBG(BTRFS, ul_debug(" subvolid/subvol not found, checking default"));
1268
1269 default_id = btrfs_get_default_subvol_id(mnt_fs_get_target(fs));
1270 if (default_id == UINT64_MAX)
1271 goto not_found;
1272
1273 /* Volume has default subvolume. Check if it matches to
1274 * the one in mountinfo.
1275 *
1276 * Only kernel >= 4.2 reports subvolid. On older
1277 * kernels, there is no reasonable way to detect which
1278 * subvolume was mounted.
1279 */
1280 target = mnt_resolve_target(mnt_fs_get_target(fs), tb->cache);
1281 if (!target)
1282 goto err;
1283
1284 snprintf(default_id_str, sizeof(default_id_str), "%llu",
1285 (unsigned long long int) default_id);
1286
c59409b9 1287 DBG(BTRFS, ul_debug(" trying target=%s default subvolid=%s",
9aa3173b
KZ
1288 target, default_id_str));
1289
1290 f = mnt_table_find_target_with_option(tb, target,
1291 "subvolid", default_id_str,
1292 MNT_ITER_BACKWARD);
1293 if (!tb->cache)
1294 free(target);
1295 if (!f)
1296 goto not_found;
1297
1298 /* Instead of set of BACKREF queries constructing
1299 * subvol path, use the one in mountinfo. Kernel does
1300 * the evaluation for us.
1301 */
1302 DBG(BTRFS, ul_debug("setting FS root: btrfs default subvolid = %s",
1303 default_id_str));
1304
1305 if (mnt_fs_get_option(f, "subvol", &vol, &volsz) != 0)
1306 goto not_found;
1307 }
1308
1309 DBG(BTRFS, ul_debug(" using subvol=%s", vol));
1310 sz = volsz;
1311 if (*vol != '/')
1312 sz++;
1313 *root = malloc(sz + 1);
1314 if (!*root)
1315 goto err;
1316 p = *root;
1317 if (*vol != '/')
1318 *p++ = '/';
1319 memcpy(p, vol, volsz);
1320 *(*root + sz) = '\0';
1321 return 0;
1322
1323not_found:
1324 DBG(BTRFS, ul_debug(" not found btrfs volume setting"));
1325 return 1;
1326err:
1327 DBG(BTRFS, ul_debug(" error on btrfs volume setting evaluation"));
1328 return errno ? -errno : -1;
1329}
1330#endif /* HAVE_BTRFS_SUPPORT */
1331
5c60a0ea 1332/*
7293e97a
KZ
1333 * tb: /proc/self/mountinfo
1334 * fs: filesystem
1335 * mountflags: MS_BIND or 0
d58b3157 1336 * fsroot: fs-root that will probably be used in the mountinfo file
5c60a0ea
KZ
1337 * for @fs after mount(2)
1338 *
1339 * For btrfs subvolumes this function returns NULL, but @fsroot properly set.
1340 *
e9cd2e2b
KZ
1341 * If @tb is NULL then defaults to '/'.
1342 *
5c60a0ea
KZ
1343 * Returns: entry from @tb that will be used as a source for @fs if the @fs is
1344 * bindmount.
7293e97a
KZ
1345 *
1346 * Don't export to library API!
5c60a0ea
KZ
1347 */
1348struct libmnt_fs *mnt_table_get_fs_root(struct libmnt_table *tb,
1349 struct libmnt_fs *fs,
1350 unsigned long mountflags,
1351 char **fsroot)
1352{
cc06a01e
KZ
1353 char *root = NULL;
1354 const char *mnt = NULL;
5c60a0ea
KZ
1355 const char *fstype;
1356 struct libmnt_fs *src_fs = NULL;
1357
5c60a0ea
KZ
1358 assert(fs);
1359 assert(fsroot);
1360
83a78332 1361 DBG(TAB, ul_debug("lookup fs-root for '%s'", mnt_fs_get_source(fs)));
5c60a0ea
KZ
1362
1363 fstype = mnt_fs_get_fstype(fs);
1364
c4c66355 1365 if (tb && (mountflags & MS_BIND)) {
5c60a0ea 1366 const char *src, *src_root;
16b8db49 1367 char *xsrc = NULL;
5c60a0ea 1368
83a78332 1369 DBG(TAB, ul_debug("fs-root for bind"));
5c60a0ea 1370
16b8db49 1371 src = xsrc = mnt_resolve_spec(mnt_fs_get_source(fs), tb->cache);
cc06a01e 1372 if (src) {
624e147b 1373 struct libmnt_fs *f = mnt_table_find_mountpoint(tb,
cc06a01e 1374 src, MNT_ITER_BACKWARD);
624e147b
SK
1375 if (f)
1376 mnt = mnt_fs_get_target(f);
cc06a01e 1377 }
16b8db49 1378 if (mnt)
cc06a01e 1379 root = remove_mountpoint_from_path(src, mnt);
5c60a0ea 1380
16b8db49
KZ
1381 if (xsrc && !tb->cache) {
1382 free(xsrc);
1383 src = NULL;
1384 }
5c60a0ea
KZ
1385 if (!mnt)
1386 goto err;
1387
5c60a0ea
KZ
1388 src_fs = mnt_table_find_target(tb, mnt, MNT_ITER_BACKWARD);
1389 if (!src_fs) {
83a78332 1390 DBG(TAB, ul_debug("not found '%s' in mountinfo -- using default", mnt));
5c60a0ea
KZ
1391 goto dflt;
1392 }
1393
352740e8 1394 /* It's possible that fstab_fs source is subdirectory on btrfs
2cd28fc8 1395 * subvolume or another bind mount. For example:
352740e8
KZ
1396 *
1397 * /dev/sdc /mnt/test btrfs subvol=/anydir
2cd28fc8 1398 * /dev/sdc /mnt/test btrfs defaults
352740e8
KZ
1399 * /mnt/test/foo /mnt/test2 auto bind
1400 *
1401 * in this case, the root for /mnt/test2 will be /anydir/foo on
1402 * /dev/sdc. It means we have to compose the final root from
1403 * root and src_root.
5c60a0ea
KZ
1404 */
1405 src_root = mnt_fs_get_root(src_fs);
352740e8
KZ
1406
1407 DBG(FS, ul_debugobj(fs, "source root: %s, source FS root: %s", root, src_root));
1408
5c60a0ea 1409 if (src_root && !startswith(root, src_root)) {
352740e8
KZ
1410 if (strcmp(root, "/") == 0) {
1411 free(root);
1412 root = strdup(src_root);
1413 if (!root)
1414 goto err;
1415 } else {
1416 char *tmp;
1417 if (asprintf(&tmp, "%s%s", src_root, root) < 0)
1418 goto err;
1419 free(root);
1420 root = tmp;
1421 }
5c60a0ea
KZ
1422 }
1423 }
1424
5a971329 1425#ifdef HAVE_BTRFS_SUPPORT
5c60a0ea
KZ
1426 /*
1427 * btrfs-subvolume mount -- get subvolume name and use it as a root-fs path
1428 */
e9cd2e2b 1429 else if (tb && fstype && (!strcmp(fstype, "btrfs") || !strcmp(fstype, "auto"))) {
9aa3173b 1430 if (get_btrfs_fs_root(tb, fs, &root) < 0)
5c60a0ea 1431 goto err;
5c60a0ea 1432 }
5a971329
KZ
1433#endif /* HAVE_BTRFS_SUPPORT */
1434
5c60a0ea
KZ
1435dflt:
1436 if (!root) {
1437 root = strdup("/");
1438 if (!root)
1439 goto err;
1440 }
1441 *fsroot = root;
1442
83a78332 1443 DBG(TAB, ul_debug("FS root result: %s", root));
5c60a0ea 1444
5c60a0ea
KZ
1445 return src_fs;
1446err:
1447 free(root);
5c60a0ea
KZ
1448 return NULL;
1449}
1450
1451/**
37290a53 1452 * mnt_table_is_fs_mounted:
5c60a0ea
KZ
1453 * @tb: /proc/self/mountinfo file
1454 * @fstab_fs: /etc/fstab entry
1455 *
975e14bd 1456 * Checks if the @fstab_fs entry is already in the @tb table. The "swap" is
d58b3157 1457 * ignored. This function explicitly compares the source, target and root of the
975e14bd
KZ
1458 * filesystems.
1459 *
1460 * Note that source and target are canonicalized only if a cache for @tb is
1461 * defined (see mnt_table_set_cache()). The target canonicalization may
d58b3157 1462 * trigger automount on autofs mountpoints!
975e14bd
KZ
1463 *
1464 * Don't use it if you want to know if a device is mounted, just use
d58b3157 1465 * mnt_table_find_source() on the device.
975e14bd
KZ
1466 *
1467 * This function is designed mostly for "mount -a".
5c60a0ea 1468 *
5c60a0ea
KZ
1469 * Returns: 0 or 1
1470 */
1471int mnt_table_is_fs_mounted(struct libmnt_table *tb, struct libmnt_fs *fstab_fs)
1472{
449a7646
KZ
1473 struct libmnt_iter itr;
1474 struct libmnt_fs *fs;
1475
5c60a0ea 1476 char *root = NULL;
975e14bd
KZ
1477 const char *src = NULL, *tgt = NULL;
1478 char *xtgt = NULL;
7293e97a 1479 int rc = 0;
d828dfdf 1480 dev_t devno = 0;
5c60a0ea 1481
dc7c3d65 1482 DBG(FS, ul_debugobj(fstab_fs, "mnt_table_is_fs_mounted: target=%s, source=%s",
d58b9706
KZ
1483 mnt_fs_get_target(fstab_fs),
1484 mnt_fs_get_source(fstab_fs)));
ae978c4d 1485
a2f17bb2 1486 if (mnt_fs_is_swaparea(fstab_fs) || mnt_table_is_empty(tb)) {
83a78332 1487 DBG(FS, ul_debugobj(fstab_fs, "- ignore (swap or no data)"));
5c60a0ea 1488 return 0;
ae978c4d 1489 }
5c60a0ea 1490
7293e97a
KZ
1491 if (is_mountinfo(tb)) {
1492 /* @tb is mountinfo, so we can try to use fs-roots */
c9f63764 1493 struct libmnt_fs *rootfs;
7293e97a 1494 int flags = 0;
5c60a0ea 1495
7293e97a
KZ
1496 if (mnt_fs_get_option(fstab_fs, "bind", NULL, NULL) == 0)
1497 flags = MS_BIND;
1498
c9f63764
SK
1499 rootfs = mnt_table_get_fs_root(tb, fstab_fs, flags, &root);
1500 if (rootfs)
1501 src = mnt_fs_get_srcpath(rootfs);
7293e97a
KZ
1502 }
1503
975e14bd 1504 if (!src)
14f66ad6 1505 src = mnt_fs_get_source(fstab_fs);
5c60a0ea 1506
975e14bd
KZ
1507 if (src && tb->cache && !mnt_fs_is_pseudofs(fstab_fs))
1508 src = mnt_resolve_spec(src, tb->cache);
1509
d828dfdf
KZ
1510 if (src && root) {
1511 struct stat st;
1512
1513 devno = mnt_fs_get_devno(fstab_fs);
1514 if (!devno && stat(src, &st) == 0 && S_ISBLK(st.st_mode))
1515 devno = st.st_rdev;
1516 }
1517
975e14bd 1518 tgt = mnt_fs_get_target(fstab_fs);
5c60a0ea 1519
ae978c4d 1520 if (!tgt || !src) {
83a78332 1521 DBG(FS, ul_debugobj(fstab_fs, "- ignore (no source/target)"));
449a7646 1522 goto done;
ae978c4d 1523 }
449a7646 1524 mnt_reset_iter(&itr, MNT_ITER_FORWARD);
5c60a0ea 1525
dc7c3d65 1526 DBG(FS, ul_debugobj(fstab_fs, "mnt_table_is_fs_mounted: src=%s, tgt=%s, root=%s", src, tgt, root));
352740e8 1527
449a7646 1528 while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
975e14bd 1529
d828dfdf
KZ
1530 int eq = mnt_fs_streq_srcpath(fs, src);
1531
1532 if (!eq && devno && mnt_fs_get_devno(fs) == devno)
1533 eq = 1;
1534
1535 if (!eq) {
b2cbe99f
KZ
1536 /* The source does not match. Maybe the source is a loop
1537 * device backing file.
1538 */
1539 uint64_t offset = 0;
1540 char *val;
1541 size_t len;
dc7c3d65 1542 int flags = 0;
b2cbe99f 1543
dc7c3d65 1544 if (!mnt_fs_get_srcpath(fs) ||
b2cbe99f
KZ
1545 !startswith(mnt_fs_get_srcpath(fs), "/dev/loop"))
1546 continue; /* does not look like loopdev */
1547
dc7c3d65
KZ
1548 if (mnt_fs_get_option(fstab_fs, "offset", &val, &len) == 0) {
1549 if (mnt_parse_offset(val, len, &offset)) {
1550 DBG(FS, ul_debugobj(fstab_fs, "failed to parse offset="));
1551 continue;
1552 }
b2cbe99f 1553 flags = LOOPDEV_FL_OFFSET;
dc7c3d65 1554 }
b2cbe99f 1555
d58b9706 1556 DBG(FS, ul_debugobj(fs, "checking for loop: src=%s", mnt_fs_get_srcpath(fs)));
e624bc55 1557#if __linux__
d58b9706
KZ
1558 if (!loopdev_is_used(mnt_fs_get_srcpath(fs), src, offset, flags))
1559 continue;
1560
1561 DBG(FS, ul_debugobj(fs, "used loop"));
e624bc55 1562#endif
b2cbe99f
KZ
1563 }
1564
449a7646
KZ
1565 if (root) {
1566 const char *r = mnt_fs_get_root(fs);
1567 if (!r || strcmp(r, root) != 0)
975e14bd 1568 continue;
449a7646 1569 }
5c60a0ea 1570
449a7646 1571 /*
d58b3157 1572 * Compare target, try to minimize the number of situations when we
449a7646
KZ
1573 * need to canonicalize the path to avoid readlink() on
1574 * mountpoints.
1575 */
1576 if (!xtgt) {
1577 if (mnt_fs_streq_target(fs, tgt))
5c60a0ea 1578 break;
449a7646
KZ
1579 if (tb->cache)
1580 xtgt = mnt_resolve_path(tgt, tb->cache);
5c60a0ea 1581 }
449a7646
KZ
1582 if (xtgt && mnt_fs_streq_target(fs, xtgt))
1583 break;
5c60a0ea
KZ
1584 }
1585
449a7646
KZ
1586 if (fs)
1587 rc = 1; /* success */
1588done:
5c60a0ea 1589 free(root);
b2cbe99f 1590
83a78332 1591 DBG(TAB, ul_debugobj(tb, "mnt_table_is_fs_mounted: %s [rc=%d]", src, rc));
5c60a0ea
KZ
1592 return rc;
1593}
1594
6bd8b7a7 1595#ifdef TEST_PROGRAM
dcc15ce5 1596#include "pathnames.h"
fbb3eb85 1597
68164f6c 1598static int parser_errcb(struct libmnt_table *tb, const char *filename, int line)
fbb3eb85
KZ
1599{
1600 fprintf(stderr, "%s:%d: parse error\n", filename, line);
c3b0d5b3 1601
d58b3157 1602 return 1; /* all errors are recoverable -- this is the default */
fbb3eb85
KZ
1603}
1604
5fde1d9f 1605static struct libmnt_table *create_table(const char *file, int comments)
6bd8b7a7 1606{
68164f6c 1607 struct libmnt_table *tb;
6bd8b7a7
KZ
1608
1609 if (!file)
1610 return NULL;
68164f6c 1611 tb = mnt_new_table();
6bd8b7a7
KZ
1612 if (!tb)
1613 goto err;
fbb3eb85 1614
cb90e24e 1615 mnt_table_enable_comments(tb, comments);
68164f6c 1616 mnt_table_set_parser_errcb(tb, parser_errcb);
fbb3eb85 1617
68164f6c 1618 if (mnt_table_parse_file(tb, file) != 0)
6bd8b7a7 1619 goto err;
6bd8b7a7
KZ
1620 return tb;
1621err:
c3b0d5b3 1622 fprintf(stderr, "%s: parsing failed\n", file);
c9f1585e 1623 mnt_unref_table(tb);
6bd8b7a7
KZ
1624 return NULL;
1625}
1626
5fde1d9f 1627static int test_copy_fs(struct libmnt_test *ts, int argc, char *argv[])
6d94f2dc 1628{
68164f6c
KZ
1629 struct libmnt_table *tb;
1630 struct libmnt_fs *fs;
059c696f 1631 int rc = -1;
6d94f2dc 1632
cb90e24e 1633 tb = create_table(argv[1], FALSE);
6d94f2dc
KZ
1634 if (!tb)
1635 return -1;
1636
68164f6c 1637 fs = mnt_table_find_target(tb, "/", MNT_ITER_FORWARD);
6d94f2dc 1638 if (!fs)
059c696f 1639 goto done;
6d94f2dc
KZ
1640
1641 printf("ORIGINAL:\n");
1642 mnt_fs_print_debug(fs, stdout);
1643
309139c7 1644 fs = mnt_copy_fs(NULL, fs);
6d94f2dc 1645 if (!fs)
059c696f 1646 goto done;
6d94f2dc
KZ
1647
1648 printf("COPY:\n");
1649 mnt_fs_print_debug(fs, stdout);
26d0c0ae 1650 mnt_unref_fs(fs);
059c696f
KZ
1651 rc = 0;
1652done:
c9f1585e 1653 mnt_unref_table(tb);
059c696f 1654 return rc;
6d94f2dc
KZ
1655}
1656
5fde1d9f 1657static int test_parse(struct libmnt_test *ts, int argc, char *argv[])
6bd8b7a7 1658{
68164f6c
KZ
1659 struct libmnt_table *tb = NULL;
1660 struct libmnt_iter *itr = NULL;
1661 struct libmnt_fs *fs;
059c696f 1662 int rc = -1;
cb90e24e
OO
1663 int parse_comments = FALSE;
1664
1665 if (argc == 3 && !strcmp(argv[2], "--comments"))
1666 parse_comments = TRUE;
6bd8b7a7 1667
cb90e24e 1668 tb = create_table(argv[1], parse_comments);
6bd8b7a7
KZ
1669 if (!tb)
1670 return -1;
1671
efe73c3e
KZ
1672 itr = mnt_new_iter(MNT_ITER_FORWARD);
1673 if (!itr)
059c696f 1674 goto done;
fbb3eb85 1675
cb90e24e
OO
1676 if (mnt_table_get_intro_comment(tb))
1677 fprintf(stdout, "Initial comment:\n\"%s\"\n",
1678 mnt_table_get_intro_comment(tb));
1679
68164f6c 1680 while(mnt_table_next_fs(tb, itr, &fs) == 0)
efe73c3e 1681 mnt_fs_print_debug(fs, stdout);
cb90e24e 1682
3035ba93 1683 if (mnt_table_get_trailing_comment(tb))
cb90e24e 1684 fprintf(stdout, "Trailing comment:\n\"%s\"\n",
3035ba93 1685 mnt_table_get_trailing_comment(tb));
059c696f
KZ
1686 rc = 0;
1687done:
efe73c3e 1688 mnt_free_iter(itr);
c9f1585e 1689 mnt_unref_table(tb);
059c696f 1690 return rc;
6bd8b7a7
KZ
1691}
1692
5fde1d9f 1693static int test_find(struct libmnt_test *ts, int argc, char *argv[], int dr)
6bd8b7a7 1694{
68164f6c
KZ
1695 struct libmnt_table *tb;
1696 struct libmnt_fs *fs = NULL;
1697 struct libmnt_cache *mpc = NULL;
6bd8b7a7 1698 const char *file, *find, *what;
059c696f 1699 int rc = -1;
6bd8b7a7
KZ
1700
1701 if (argc != 4) {
1702 fprintf(stderr, "try --help\n");
059c696f 1703 return -EINVAL;
6bd8b7a7
KZ
1704 }
1705
1706 file = argv[1], find = argv[2], what = argv[3];
1707
cb90e24e 1708 tb = create_table(file, FALSE);
6bd8b7a7 1709 if (!tb)
059c696f 1710 goto done;
6bd8b7a7
KZ
1711
1712 /* create a cache for canonicalized paths */
1713 mpc = mnt_new_cache();
1714 if (!mpc)
059c696f 1715 goto done;
68164f6c 1716 mnt_table_set_cache(tb, mpc);
0105691d 1717 mnt_unref_cache(mpc);
6bd8b7a7
KZ
1718
1719 if (strcasecmp(find, "source") == 0)
68164f6c 1720 fs = mnt_table_find_source(tb, what, dr);
6bd8b7a7 1721 else if (strcasecmp(find, "target") == 0)
68164f6c 1722 fs = mnt_table_find_target(tb, what, dr);
6bd8b7a7
KZ
1723
1724 if (!fs)
1725 fprintf(stderr, "%s: not found %s '%s'\n", file, find, what);
1726 else {
5e31c2c8 1727 mnt_fs_print_debug(fs, stdout);
059c696f 1728 rc = 0;
6bd8b7a7 1729 }
059c696f 1730done:
c9f1585e 1731 mnt_unref_table(tb);
059c696f 1732 return rc;
6bd8b7a7
KZ
1733}
1734
5fde1d9f 1735static int test_find_bw(struct libmnt_test *ts, int argc, char *argv[])
6bd8b7a7
KZ
1736{
1737 return test_find(ts, argc, argv, MNT_ITER_BACKWARD);
1738}
1739
5fde1d9f 1740static int test_find_fw(struct libmnt_test *ts, int argc, char *argv[])
6bd8b7a7
KZ
1741{
1742 return test_find(ts, argc, argv, MNT_ITER_FORWARD);
1743}
1744
5fde1d9f 1745static int test_find_pair(struct libmnt_test *ts, int argc, char *argv[])
059c696f 1746{
68164f6c
KZ
1747 struct libmnt_table *tb;
1748 struct libmnt_fs *fs;
975e14bd 1749 struct libmnt_cache *mpc = NULL;
059c696f
KZ
1750 int rc = -1;
1751
cb90e24e 1752 tb = create_table(argv[1], FALSE);
059c696f
KZ
1753 if (!tb)
1754 return -1;
975e14bd
KZ
1755 mpc = mnt_new_cache();
1756 if (!mpc)
1757 goto done;
1758 mnt_table_set_cache(tb, mpc);
0105691d 1759 mnt_unref_cache(mpc);
059c696f 1760
68164f6c 1761 fs = mnt_table_find_pair(tb, argv[2], argv[3], MNT_ITER_FORWARD);
059c696f
KZ
1762 if (!fs)
1763 goto done;
1764
1765 mnt_fs_print_debug(fs, stdout);
1766 rc = 0;
1767done:
c9f1585e 1768 mnt_unref_table(tb);
059c696f
KZ
1769 return rc;
1770}
1771
5fde1d9f 1772static int test_find_mountpoint(struct libmnt_test *ts, int argc, char *argv[])
dcc15ce5
KZ
1773{
1774 struct libmnt_table *tb;
1775 struct libmnt_fs *fs;
1776 struct libmnt_cache *mpc = NULL;
1777 int rc = -1;
1778
1779 tb = mnt_new_table_from_file(_PATH_PROC_MOUNTINFO);
1780 if (!tb)
1781 return -1;
1782 mpc = mnt_new_cache();
1783 if (!mpc)
1784 goto done;
1785 mnt_table_set_cache(tb, mpc);
0105691d 1786 mnt_unref_cache(mpc);
dcc15ce5
KZ
1787
1788 fs = mnt_table_find_mountpoint(tb, argv[1], MNT_ITER_BACKWARD);
1789 if (!fs)
1790 goto done;
1791
1792 mnt_fs_print_debug(fs, stdout);
1793 rc = 0;
1794done:
c9f1585e 1795 mnt_unref_table(tb);
dcc15ce5
KZ
1796 return rc;
1797}
1798
5c60a0ea
KZ
1799static int test_is_mounted(struct libmnt_test *ts, int argc, char *argv[])
1800{
1801 struct libmnt_table *tb = NULL, *fstab = NULL;
1802 struct libmnt_fs *fs;
1803 struct libmnt_iter *itr = NULL;
975e14bd 1804 struct libmnt_cache *mpc = NULL;
58c87bd0 1805 int writable = 0;
dc7c3d65
KZ
1806 const char *path = NULL;
1807
1808 if (mnt_has_regular_mtab(&path, &writable) == 1 && writable == 0)
1809 tb = mnt_new_table_from_file(path);
1810 else
1811 tb = mnt_new_table_from_file("/proc/self/mountinfo");
5c60a0ea 1812
5c60a0ea
KZ
1813 if (!tb) {
1814 fprintf(stderr, "failed to parse mountinfo\n");
1815 return -1;
1816 }
1817
cb90e24e 1818 fstab = create_table(argv[1], FALSE);
5c60a0ea
KZ
1819 if (!fstab)
1820 goto done;
1821
1822 itr = mnt_new_iter(MNT_ITER_FORWARD);
1823 if (!itr)
1824 goto done;
1825
975e14bd
KZ
1826 mpc = mnt_new_cache();
1827 if (!mpc)
1828 goto done;
1829 mnt_table_set_cache(tb, mpc);
0105691d 1830 mnt_unref_cache(mpc);
975e14bd 1831
dc7c3d65 1832 while (mnt_table_next_fs(fstab, itr, &fs) == 0) {
5c60a0ea
KZ
1833 if (mnt_table_is_fs_mounted(tb, fs))
1834 printf("%s already mounted on %s\n",
1835 mnt_fs_get_source(fs),
1836 mnt_fs_get_target(fs));
1837 else
1838 printf("%s not mounted on %s\n",
1839 mnt_fs_get_source(fs),
1840 mnt_fs_get_target(fs));
1841 }
1842
5c60a0ea 1843done:
c9f1585e
KZ
1844 mnt_unref_table(tb);
1845 mnt_unref_table(fstab);
5c60a0ea 1846 mnt_free_iter(itr);
58c87bd0 1847 return 0;
5c60a0ea
KZ
1848}
1849
51fffa7b
KZ
1850/* returns 0 if @a and @b targets are the same */
1851static int test_uniq_cmp(struct libmnt_table *tb __attribute__((__unused__)),
1852 struct libmnt_fs *a,
1853 struct libmnt_fs *b)
1854{
1855 assert(a);
1856 assert(b);
1857
1858 return mnt_fs_streq_target(a, mnt_fs_get_target(b)) ? 0 : 1;
1859}
1860
1861static int test_uniq(struct libmnt_test *ts, int argc, char *argv[])
1862{
1863 struct libmnt_table *tb;
1864 int rc = -1;
1865
1866 if (argc != 2) {
1867 fprintf(stderr, "try --help\n");
1868 return -EINVAL;
1869 }
1870
1871 tb = create_table(argv[1], FALSE);
1872 if (!tb)
1873 goto done;
1874
1875 if (mnt_table_uniq_fs(tb, 0, test_uniq_cmp) == 0) {
1876 struct libmnt_iter *itr = mnt_new_iter(MNT_ITER_FORWARD);
1877 struct libmnt_fs *fs;
1878 if (!itr)
1879 goto done;
1880 while (mnt_table_next_fs(tb, itr, &fs) == 0)
1881 mnt_fs_print_debug(fs, stdout);
1882 mnt_free_iter(itr);
1883 rc = 0;
1884 }
1885done:
1886 mnt_unref_table(tb);
1887 return rc;
1888}
1889
cc06a01e 1890
6bd8b7a7
KZ
1891int main(int argc, char *argv[])
1892{
68164f6c 1893 struct libmnt_test tss[] = {
cb90e24e 1894 { "--parse", test_parse, "<file> [--comments] parse and print tab" },
6bd8b7a7
KZ
1895 { "--find-forward", test_find_fw, "<file> <source|target> <string>" },
1896 { "--find-backward", test_find_bw, "<file> <source|target> <string>" },
51fffa7b 1897 { "--uniq-target", test_uniq, "<file>" },
059c696f 1898 { "--find-pair", test_find_pair, "<file> <source> <target>" },
dcc15ce5 1899 { "--find-mountpoint", test_find_mountpoint, "<path>" },
6d94f2dc 1900 { "--copy-fs", test_copy_fs, "<file> copy root FS from the file" },
dc7c3d65 1901 { "--is-mounted", test_is_mounted, "<fstab> check what from fstab is already mounted" },
6bd8b7a7
KZ
1902 { NULL }
1903 };
1904
1905 return mnt_run_test(tss, argc, argv);
1906}
1907
1908#endif /* TEST_PROGRAM */