]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libmount/src/tab.c
libmount: add new function to docs
[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"
6bd8b7a7
KZ
49
50/**
68164f6c 51 * mnt_new_table:
6bd8b7a7 52 *
68164f6c 53 * The tab is a container for struct libmnt_fs entries that usually represents a fstab,
6bd8b7a7
KZ
54 * mtab or mountinfo file from your system.
55 *
68164f6c 56 * See also mnt_table_parse_file().
6bd8b7a7 57 *
192c6aad 58 * Returns: newly allocated tab struct.
6bd8b7a7 59 */
68164f6c 60struct libmnt_table *mnt_new_table(void)
6bd8b7a7 61{
68164f6c 62 struct libmnt_table *tb = NULL;
6bd8b7a7 63
68164f6c 64 tb = calloc(1, sizeof(*tb));
6bd8b7a7 65 if (!tb)
9ed7507c
KZ
66 return NULL;
67
3f31a959 68 DBG(TAB, mnt_debug_h(tb, "alloc"));
6bd8b7a7 69
6bd8b7a7
KZ
70 INIT_LIST_HEAD(&tb->ents);
71 return tb;
6bd8b7a7
KZ
72}
73
74/**
18486fbb 75 * mnt_reset_table:
3d735589 76 * @tb: tab pointer
6bd8b7a7 77 *
d58b3157 78 * Deallocates all entries (filesystems) from the table.
18486fbb
KZ
79 *
80 * Returns: 0 on success or negative number in case of error.
6bd8b7a7 81 */
18486fbb 82int mnt_reset_table(struct libmnt_table *tb)
6bd8b7a7
KZ
83{
84 if (!tb)
18486fbb 85 return -EINVAL;
6bd8b7a7 86
18486fbb 87 DBG(TAB, mnt_debug_h(tb, "reset"));
3f31a959 88
6bd8b7a7 89 while (!list_empty(&tb->ents)) {
68164f6c
KZ
90 struct libmnt_fs *fs = list_entry(tb->ents.next,
91 struct libmnt_fs, ents);
6bd8b7a7
KZ
92 mnt_free_fs(fs);
93 }
94
0983b5f7 95 tb->nents = 0;
18486fbb
KZ
96 return 0;
97}
98
99/**
100 * mnt_free_table:
101 * @tb: tab pointer
102 *
103 * Deallocates tab struct and all entries.
104 */
105void mnt_free_table(struct libmnt_table *tb)
106{
107 if (!tb)
108 return;
109
110 mnt_reset_table(tb);
111
112 DBG(TAB, mnt_debug_h(tb, "free"));
cb90e24e
OO
113 free(tb->comm_intro);
114 free(tb->comm_tail);
6bd8b7a7
KZ
115 free(tb);
116}
117
118/**
68164f6c 119 * mnt_table_get_nents:
6bd8b7a7
KZ
120 * @tb: pointer to tab
121 *
192c6aad 122 * Returns: number of valid entries in tab.
6bd8b7a7 123 */
68164f6c 124int mnt_table_get_nents(struct libmnt_table *tb)
6bd8b7a7
KZ
125{
126 assert(tb);
127 return tb ? tb->nents : 0;
128}
129
2bc04c11
KZ
130/**
131 * mnt_table_set_userdata:
132 * @tb: pointer to tab
133 * @data: pointer to user data
134 *
135 * Sets pointer to the private user data.
136 *
137 * Returns: 0 on success or negative number in case of error.
138 */
139int mnt_table_set_userdata(struct libmnt_table *tb, void *data)
140{
141 assert(tb);
142 if (!tb)
143 return -EINVAL;
144
145 tb->userdata = data;
146 return 0;
147}
148
149/**
150 * mnt_table_get_userdata:
151 * @tb: pointer to tab
152 *
153 * Returns: pointer to user's data.
154 */
155void *mnt_table_get_userdata(struct libmnt_table *tb)
156{
157 assert(tb);
158 return tb ? tb->userdata : NULL;
159}
160
cb90e24e
OO
161/**
162 * mnt_table_enable_comments:
163 * @tb: pointer to tab
7b1333fa 164 * @enable: TRUE or FALSE
cb90e24e
OO
165 *
166 * Enables parsing of comments.
167 *
168 * The initial (intro) file comment is accessible by
169 * mnt_table_get_intro_comment(). The intro and the comment of the first fstab
170 * entry has to be separated by blank line. The filesystem comments are
d58b3157 171 * accessible by mnt_fs_get_comment(). The trailing fstab comment is accessible
3035ba93 172 * by mnt_table_get_trailing_comment().
cb90e24e
OO
173 *
174 * <informalexample>
175 * <programlisting>
176 * #
177 * # Intro comment
178 * #
179 *
180 * # this comments belongs to the first fs
181 * LABEL=foo /mnt/foo auto defaults 1 2
182 * # this comments belongs to the second fs
183 * LABEL=bar /mnt/bar auto defaults 1 2
184 * # tailing comment
185 * </programlisting>
186 * </informalexample>
187 */
188void mnt_table_enable_comments(struct libmnt_table *tb, int enable)
189{
190 assert(tb);
191 if (tb)
192 tb->comms = enable;
193}
194
e670df45
KZ
195/**
196 * mnt_table_with_comments:
197 * @tb: pointer to table
198 *
199 * Returns: 1 if comments parsing is enabled, or 0.
200 */
201int mnt_table_with_comments(struct libmnt_table *tb)
202{
203 assert(tb);
204 return tb ? tb->comms : 0;
205}
206
cb90e24e
OO
207/**
208 * mnt_table_get_intro_comment:
209 * @tb: pointer to tab
210 *
211 * Returns: initial comment in tb
212 */
213const char *mnt_table_get_intro_comment(struct libmnt_table *tb)
214{
215 assert(tb);
216 return tb ? tb->comm_intro : NULL;
217}
218
219/**
220 * mnt_table_set_into_comment:
221 * @tb: pointer to tab
222 * @comm: comment or NULL
223 *
d58b3157 224 * Sets the initial comment in tb.
cb90e24e
OO
225 *
226 * Returns: 0 on success or negative number in case of error.
227 */
228int mnt_table_set_intro_comment(struct libmnt_table *tb, const char *comm)
229{
230 char *p = NULL;
231
232 assert(tb);
233 if (!tb)
234 return -EINVAL;
235 if (comm) {
236 p = strdup(comm);
237 if (!p)
238 return -ENOMEM;
239 }
240 free(tb->comm_intro);
241 tb->comm_intro = p;
242 return 0;
243}
244
245/**
246 * mnt_table_append_into_comment:
247 * @tb: pointer to tab
248 * @comm: comment of NULL
249 *
250 * Appends the initial comment in tb.
251 *
252 * Returns: 0 on success or negative number in case of error.
253 */
254int mnt_table_append_intro_comment(struct libmnt_table *tb, const char *comm)
255{
256 assert(tb);
257 if (!tb)
258 return -EINVAL;
259 return append_string(&tb->comm_intro, comm);
260}
261
262/**
3035ba93 263 * mnt_table_get_trailing_comment:
cb90e24e
OO
264 * @tb: pointer to tab
265 *
d58b3157 266 * Returns: table trailing comment
cb90e24e 267 */
3035ba93 268const char *mnt_table_get_trailing_comment(struct libmnt_table *tb)
cb90e24e
OO
269{
270 assert(tb);
271 return tb ? tb->comm_tail : NULL;
272}
273
274/**
3035ba93 275 * mnt_table_set_trailing_comment
cb90e24e 276 * @tb: pointer to tab
7b1333fa 277 * @comm: comment string
cb90e24e 278 *
d58b3157 279 * Sets the trailing comment in table.
cb90e24e
OO
280 *
281 * Returns: 0 on success or negative number in case of error.
282 */
3035ba93 283int mnt_table_set_trailing_comment(struct libmnt_table *tb, const char *comm)
cb90e24e
OO
284{
285 char *p = NULL;
286
287 assert(tb);
288 if (!tb)
289 return -EINVAL;
290 if (comm) {
291 p = strdup(comm);
292 if (!p)
293 return -ENOMEM;
294 }
295 free(tb->comm_tail);
296 tb->comm_tail = p;
297 return 0;
298}
299
300/**
3035ba93 301 * mnt_table_append_trailing_comment:
cb90e24e
OO
302 * @tb: pointer to tab
303 * @comm: comment of NULL
304 *
d58b3157 305 * Appends to the trailing table comment.
cb90e24e
OO
306 *
307 * Returns: 0 on success or negative number in case of error.
308 */
3035ba93 309int mnt_table_append_trailing_comment(struct libmnt_table *tb, const char *comm)
cb90e24e
OO
310{
311 assert(tb);
312 if (!tb)
313 return -EINVAL;
314 return append_string(&tb->comm_tail, comm);
315}
316
6bd8b7a7 317/**
68164f6c 318 * mnt_table_set_cache:
6bd8b7a7 319 * @tb: pointer to tab
68164f6c 320 * @mpc: pointer to struct libmnt_cache instance
6bd8b7a7 321 *
d58b3157 322 * Sets up a cache for canonicalized paths and evaluated tags (LABEL/UUID). The
68164f6c 323 * cache is recommended for mnt_table_find_*() functions.
6bd8b7a7
KZ
324 *
325 * The cache could be shared between more tabs. Be careful when you share the
326 * same cache between more threads -- currently the cache does not provide any
327 * locking method.
328 *
329 * See also mnt_new_cache().
330 *
59ae0ddd 331 * Returns: 0 on success or negative number in case of error.
6bd8b7a7 332 */
68164f6c 333int mnt_table_set_cache(struct libmnt_table *tb, struct libmnt_cache *mpc)
6bd8b7a7
KZ
334{
335 assert(tb);
336 if (!tb)
59ae0ddd 337 return -EINVAL;
6bd8b7a7
KZ
338 tb->cache = mpc;
339 return 0;
340}
341
342/**
68164f6c 343 * mnt_table_get_cache:
6bd8b7a7
KZ
344 * @tb: pointer to tab
345 *
68164f6c 346 * Returns: pointer to struct libmnt_cache instance or NULL.
6bd8b7a7 347 */
68164f6c 348struct libmnt_cache *mnt_table_get_cache(struct libmnt_table *tb)
6bd8b7a7
KZ
349{
350 assert(tb);
351 return tb ? tb->cache : NULL;
352}
353
6bd8b7a7 354/**
68164f6c 355 * mnt_table_add_fs:
6bd8b7a7
KZ
356 * @tb: tab pointer
357 * @fs: new entry
358 *
359 * Adds a new entry to tab.
360 *
59ae0ddd 361 * Returns: 0 on success or negative number in case of error.
6bd8b7a7 362 */
68164f6c 363int mnt_table_add_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
6bd8b7a7
KZ
364{
365 assert(tb);
366 assert(fs);
367
368 if (!tb || !fs)
59ae0ddd 369 return -EINVAL;
6bd8b7a7
KZ
370
371 list_add_tail(&fs->ents, &tb->ents);
372
3f31a959
KZ
373 DBG(TAB, mnt_debug_h(tb, "add entry: %s %s",
374 mnt_fs_get_source(fs), mnt_fs_get_target(fs)));
911238af 375 tb->nents++;
6bd8b7a7
KZ
376 return 0;
377}
378
379/**
68164f6c 380 * mnt_table_remove_fs:
6bd8b7a7
KZ
381 * @tb: tab pointer
382 * @fs: new entry
383 *
59ae0ddd 384 * Returns: 0 on success or negative number in case of error.
6bd8b7a7 385 */
68164f6c 386int mnt_table_remove_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
6bd8b7a7
KZ
387{
388 assert(tb);
389 assert(fs);
390
391 if (!tb || !fs)
59ae0ddd 392 return -EINVAL;
6bd8b7a7 393 list_del(&fs->ents);
911238af 394 tb->nents--;
6bd8b7a7
KZ
395 return 0;
396}
397
26b4f9e4 398/**
68164f6c 399 * mnt_table_get_root_fs:
26b4f9e4
KZ
400 * @tb: mountinfo file (/proc/self/mountinfo)
401 * @root: returns pointer to the root filesystem (/)
402 *
d58b3157 403 * The function uses the parent ID from the mountinfo file to determine the root filesystem
c667aff9 404 * (the filesystem with the smallest ID). The function is designed mostly for
d58b3157 405 * applications where it is necessary to sort mountpoints by IDs to get the tree
c667aff9
KZ
406 * of the mountpoints (e.g. findmnt default output).
407 *
d58b3157 408 * If you're not sure, then use
c667aff9
KZ
409 *
410 * mnt_table_find_target(tb, "/", MNT_ITER_BACKWARD);
411 *
d58b3157 412 * this is more robust and usable for arbitrary tab files (including fstab).
c667aff9 413 *
d58b3157 414 * Returns: 0 on success or negative number in case of error.
26b4f9e4 415 */
68164f6c 416int mnt_table_get_root_fs(struct libmnt_table *tb, struct libmnt_fs **root)
26b4f9e4 417{
68164f6c
KZ
418 struct libmnt_iter itr;
419 struct libmnt_fs *fs;
26b4f9e4
KZ
420 int root_id = 0;
421
422 assert(tb);
423 assert(root);
424
425 if (!tb || !root)
59ae0ddd 426 return -EINVAL;
26b4f9e4 427
0ccfc837 428 DBG(TAB, mnt_debug_h(tb, "lookup root fs"));
20aae9d3 429
26b4f9e4 430 mnt_reset_iter(&itr, MNT_ITER_FORWARD);
68164f6c 431 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
26b4f9e4
KZ
432 int id = mnt_fs_get_parent_id(fs);
433 if (!id)
d58b3157 434 break; /* @tab is not a mountinfo file? */
26b4f9e4
KZ
435
436 if (!*root || id < root_id) {
437 *root = fs;
438 root_id = id;
439 }
440 }
441
59ae0ddd 442 return root_id ? 0 : -EINVAL;
26b4f9e4
KZ
443}
444
445/**
68164f6c 446 * mnt_table_next_child_fs:
26b4f9e4 447 * @tb: mountinfo file (/proc/self/mountinfo)
3d735589 448 * @itr: iterator
26b4f9e4
KZ
449 * @parent: parental FS
450 * @chld: returns the next child filesystem
451 *
d58b3157 452 * Note that filesystems are returned in the order of mounting (according to
26b4f9e4
KZ
453 * IDs in /proc/self/mountinfo).
454 *
d58b3157 455 * Returns: 0 on success, negative number in case of error or 1 at the end of list.
26b4f9e4 456 */
68164f6c
KZ
457int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
458 struct libmnt_fs *parent, struct libmnt_fs **chld)
26b4f9e4 459{
68164f6c 460 struct libmnt_fs *fs;
26b4f9e4
KZ
461 int parent_id, lastchld_id = 0, chld_id = 0;
462
463 if (!tb || !itr || !parent)
59ae0ddd 464 return -EINVAL;
26b4f9e4 465
7ba207e7 466 DBG(TAB, mnt_debug_h(tb, "lookup next child of '%s'",
3f31a959 467 mnt_fs_get_target(parent)));
20aae9d3 468
26b4f9e4
KZ
469 parent_id = mnt_fs_get_id(parent);
470 if (!parent_id)
59ae0ddd 471 return -EINVAL;
26b4f9e4
KZ
472
473 /* get ID of the previously returned child */
474 if (itr->head && itr->p != itr->head) {
68164f6c 475 MNT_ITER_ITERATE(itr, fs, struct libmnt_fs, ents);
26b4f9e4
KZ
476 lastchld_id = mnt_fs_get_id(fs);
477 }
478
479 *chld = NULL;
480
481 mnt_reset_iter(itr, MNT_ITER_FORWARD);
68164f6c 482 while(mnt_table_next_fs(tb, itr, &fs) == 0) {
26b4f9e4
KZ
483 int id;
484
485 if (mnt_fs_get_parent_id(fs) != parent_id)
486 continue;
487
488 id = mnt_fs_get_id(fs);
489
d58b3157 490 /* avoid an infinite loop. This only happens in rare cases
bf91904c
DR
491 * such as in early userspace when the rootfs is its own parent */
492 if (id == parent_id)
493 continue;
494
26b4f9e4
KZ
495 if ((!lastchld_id || id > lastchld_id) &&
496 (!*chld || id < chld_id)) {
497 *chld = fs;
498 chld_id = id;
499 }
500 }
501
502 if (!chld_id)
503 return 1; /* end of iterator */
504
505 /* set the iterator to the @chld for the next call */
68164f6c 506 mnt_table_set_iter(tb, itr, *chld);
26b4f9e4
KZ
507
508 return 0;
509}
510
6bd8b7a7 511/**
68164f6c 512 * mnt_table_next_fs:
6bd8b7a7
KZ
513 * @tb: tab pointer
514 * @itr: iterator
515 * @fs: returns the next tab entry
516 *
d58b3157 517 * Returns: 0 on success, negative number in case of error or 1 at the end of list.
6bd8b7a7 518 *
0f32f1e2 519 * Example:
3d735589
KZ
520 * <informalexample>
521 * <programlisting>
68164f6c 522 * while(mnt_table_next_fs(tb, itr, &fs) == 0) {
6bd8b7a7
KZ
523 * const char *dir = mnt_fs_get_target(fs);
524 * printf("mount point: %s\n", dir);
525 * }
68164f6c 526 * mnt_free_table(fi);
3d735589
KZ
527 * </programlisting>
528 * </informalexample>
0f32f1e2 529 *
d58b3157 530 * lists all mountpoints from fstab in reverse order.
6bd8b7a7 531 */
68164f6c 532int mnt_table_next_fs(struct libmnt_table *tb, struct libmnt_iter *itr, struct libmnt_fs **fs)
6bd8b7a7 533{
59ae0ddd 534 int rc = 1;
3fca8422 535
6bd8b7a7
KZ
536 assert(tb);
537 assert(itr);
538 assert(fs);
539
540 if (!tb || !itr || !fs)
59ae0ddd 541 return -EINVAL;
0532ba1d
KZ
542 *fs = NULL;
543
6bd8b7a7
KZ
544 if (!itr->head)
545 MNT_ITER_INIT(itr, &tb->ents);
546 if (itr->p != itr->head) {
68164f6c 547 MNT_ITER_ITERATE(itr, *fs, struct libmnt_fs, ents);
3fca8422 548 rc = 0;
6bd8b7a7
KZ
549 }
550
3fca8422
KZ
551 return rc;
552}
553
554/**
68164f6c 555 * mnt_table_find_next_fs:
3fca8422
KZ
556 * @tb: table
557 * @itr: iterator
d58b3157 558 * @match_func: function returning 1 or 0
3d735589 559 * @userdata: extra data for match_func
3fca8422
KZ
560 * @fs: returns pointer to the next matching table entry
561 *
d58b3157 562 * This function allows searching in @tb.
3fca8422 563 *
59ae0ddd 564 * Returns: negative number in case of error, 1 at end of table or 0 o success.
3fca8422 565 */
68164f6c
KZ
566int mnt_table_find_next_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
567 int (*match_func)(struct libmnt_fs *, void *), void *userdata,
568 struct libmnt_fs **fs)
3fca8422
KZ
569{
570 if (!tb || !itr || !fs || !match_func)
59ae0ddd 571 return -EINVAL;
3fca8422 572
0ccfc837 573 DBG(TAB, mnt_debug_h(tb, "lookup next fs"));
20aae9d3 574
3fca8422
KZ
575 if (!itr->head)
576 MNT_ITER_INIT(itr, &tb->ents);
577
578 do {
579 if (itr->p != itr->head)
68164f6c 580 MNT_ITER_ITERATE(itr, *fs, struct libmnt_fs, ents);
3fca8422
KZ
581 else
582 break; /* end */
583
3fca8422
KZ
584 if (match_func(*fs, userdata))
585 return 0;
586 } while(1);
587
26b4f9e4 588 *fs = NULL;
6bd8b7a7
KZ
589 return 1;
590}
591
592/**
68164f6c 593 * mnt_table_set_iter:
6bd8b7a7
KZ
594 * @tb: tab pointer
595 * @itr: iterator
596 * @fs: tab entry
597 *
598 * Sets @iter to the position of @fs in the file @tb.
599 *
59ae0ddd 600 * Returns: 0 on success, negative number in case of error.
6bd8b7a7 601 */
68164f6c 602int mnt_table_set_iter(struct libmnt_table *tb, struct libmnt_iter *itr, struct libmnt_fs *fs)
6bd8b7a7
KZ
603{
604 assert(tb);
605 assert(itr);
606 assert(fs);
607
608 if (!tb || !itr || !fs)
59ae0ddd 609 return -EINVAL;
6bd8b7a7
KZ
610
611 MNT_ITER_INIT(itr, &tb->ents);
612 itr->p = &fs->ents;
613
614 return 0;
615}
616
dcc15ce5
KZ
617/**
618 * mnt_table_find_mountpoint:
619 * @tb: tab pointer
620 * @path: directory
621 * @direction: MNT_ITER_{FORWARD,BACKWARD}
622 *
d58b3157 623 * Same as mnt_get_mountpoint(), except this function does not rely on
dcc15ce5
KZ
624 * st_dev numbers.
625 *
626 * Returns: a tab entry or NULL.
627 */
628struct libmnt_fs *mnt_table_find_mountpoint(struct libmnt_table *tb,
629 const char *path,
630 int direction)
631{
632 char *mnt;
633
7ba207e7 634 if (!tb || !path || !*path)
dcc15ce5 635 return NULL;
4cd271ad
KZ
636 if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
637 return NULL;
dcc15ce5 638
7ba207e7 639 DBG(TAB, mnt_debug_h(tb, "lookup MOUNTPOINT: '%s'", path));
dcc15ce5
KZ
640
641 mnt = strdup(path);
642 if (!mnt)
643 return NULL;
644
645 do {
646 char *p;
647 struct libmnt_fs *fs;
648
649 fs = mnt_table_find_target(tb, mnt, direction);
650 if (fs) {
651 free(mnt);
652 return fs;
653 }
654
655 p = stripoff_last_component(mnt);
656 if (!p || !*p)
657 break;
658 } while (mnt && *(mnt + 1) != '\0');
659
660 free(mnt);
661 return mnt_table_find_target(tb, "/", direction);
662}
663
6bd8b7a7 664/**
68164f6c 665 * mnt_table_find_target:
6bd8b7a7
KZ
666 * @tb: tab pointer
667 * @path: mountpoint directory
668 * @direction: MNT_ITER_{FORWARD,BACKWARD}
669 *
d58b3157
OO
670 * Try to lookup an entry in the given tab, three iterations are possible, the first
671 * with @path, the second with realpath(@path) and the third with realpath(@path)
6bd8b7a7 672 * against realpath(fs->target). The 2nd and 3rd iterations are not performed
d58b3157 673 * when the @tb cache is not set (see mnt_table_set_cache()).
6bd8b7a7 674 *
192c6aad 675 * Returns: a tab entry or NULL.
6bd8b7a7 676 */
68164f6c 677struct libmnt_fs *mnt_table_find_target(struct libmnt_table *tb, const char *path, int direction)
6bd8b7a7 678{
68164f6c
KZ
679 struct libmnt_iter itr;
680 struct libmnt_fs *fs = NULL;
6bd8b7a7
KZ
681 char *cn;
682
683 assert(tb);
684 assert(path);
685
7ba207e7 686 if (!tb || !path || !*path)
59ae0ddd 687 return NULL;
4cd271ad
KZ
688 if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
689 return NULL;
59ae0ddd 690
7ba207e7 691 DBG(TAB, mnt_debug_h(tb, "lookup TARGET: '%s'", path));
6bd8b7a7
KZ
692
693 /* native @target */
694 mnt_reset_iter(&itr, direction);
de60d08e 695 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
6699e742 696 if (mnt_fs_streq_target(fs, path))
6bd8b7a7 697 return fs;
de60d08e 698 }
6bd8b7a7
KZ
699 if (!tb->cache || !(cn = mnt_resolve_path(path, tb->cache)))
700 return NULL;
701
7ba207e7
KZ
702 DBG(TAB, mnt_debug_h(tb, "lookup canonical TARGET: '%s'", cn));
703
68164f6c 704 /* canonicalized paths in struct libmnt_table */
6bd8b7a7 705 mnt_reset_iter(&itr, direction);
68164f6c 706 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
6699e742 707 if (mnt_fs_streq_target(fs, cn))
6bd8b7a7
KZ
708 return fs;
709 }
710
fa705b54
KZ
711 /* non-canonicaled path in struct libmnt_table
712 * -- note that mountpoint in /proc/self/mountinfo is already
d58b3157 713 * canonicalized by the kernel
fa705b54 714 */
6bd8b7a7 715 mnt_reset_iter(&itr, direction);
68164f6c 716 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
6bd8b7a7 717 char *p;
9dd75aa6 718
fa705b54
KZ
719 if (!fs->target
720 || mnt_fs_is_swaparea(fs)
721 || mnt_fs_is_kernel(fs)
722 || (*fs->target == '/' && *(fs->target + 1) == '\0'))
6bd8b7a7 723 continue;
9dd75aa6 724
6bd8b7a7 725 p = mnt_resolve_path(fs->target, tb->cache);
6699e742
KZ
726 /* both canonicalized, strcmp() is fine here */
727 if (p && strcmp(cn, p) == 0)
6bd8b7a7
KZ
728 return fs;
729 }
730 return NULL;
731}
732
733/**
68164f6c 734 * mnt_table_find_srcpath:
6bd8b7a7 735 * @tb: tab pointer
f12aac6e 736 * @path: source path (devname or dirname) or NULL
6bd8b7a7
KZ
737 * @direction: MNT_ITER_{FORWARD,BACKWARD}
738 *
d58b3157
OO
739 * Try to lookup an entry in the given tab, four iterations are possible, the first
740 * with @path, the second with realpath(@path), the third with tags (LABEL, UUID, ..)
741 * from @path and the fourth with realpath(@path) against realpath(entry->srcpath).
6bd8b7a7 742 *
d58b3157 743 * The 2nd, 3rd and 4th iterations are not performed when the @tb cache is not
68164f6c 744 * set (see mnt_table_set_cache()).
6bd8b7a7 745 *
d0ce7c07
DR
746 * Note that NULL is a valid source path; it will be replaced with "none". The
747 * "none" is used in /proc/{mounts,self/mountinfo} for pseudo filesystems.
f12aac6e 748 *
192c6aad 749 * Returns: a tab entry or NULL.
6bd8b7a7 750 */
68164f6c 751struct libmnt_fs *mnt_table_find_srcpath(struct libmnt_table *tb, const char *path, int direction)
6bd8b7a7 752{
68164f6c
KZ
753 struct libmnt_iter itr;
754 struct libmnt_fs *fs = NULL;
6bd8b7a7
KZ
755 int ntags = 0;
756 char *cn;
757 const char *p;
758
759 assert(tb);
7ba207e7 760 if (!tb || !path || !*path)
dcc15ce5 761 return NULL;
4cd271ad
KZ
762 if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
763 return NULL;
6bd8b7a7 764
7ba207e7 765 DBG(TAB, mnt_debug_h(tb, "lookup SRCPATH: '%s'", path));
6bd8b7a7
KZ
766
767 /* native paths */
768 mnt_reset_iter(&itr, direction);
68164f6c 769 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
ab8c6e05 770 if (mnt_fs_streq_srcpath(fs, path))
6bd8b7a7 771 return fs;
ab8c6e05
KZ
772 if (mnt_fs_get_tag(fs, NULL, NULL) == 0)
773 ntags++;
6bd8b7a7
KZ
774 }
775
f12aac6e 776 if (!path || !tb->cache || !(cn = mnt_resolve_path(path, tb->cache)))
6bd8b7a7
KZ
777 return NULL;
778
7ba207e7
KZ
779 DBG(TAB, mnt_debug_h(tb, "lookup canonical SRCPATH: '%s'", cn));
780
68164f6c
KZ
781 /* canonicalized paths in struct libmnt_table */
782 if (ntags < mnt_table_get_nents(tb)) {
6bd8b7a7 783 mnt_reset_iter(&itr, direction);
68164f6c 784 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
ab8c6e05 785 if (mnt_fs_streq_srcpath(fs, cn))
6bd8b7a7
KZ
786 return fs;
787 }
788 }
789
790 /* evaluated tag */
3fca8422 791 if (ntags) {
ba7232a1
KZ
792 int rc = mnt_cache_read_tags(tb->cache, cn);
793
6bd8b7a7 794 mnt_reset_iter(&itr, direction);
6bd8b7a7 795
ba7232a1 796 if (rc == 0) {
3fca8422 797 /* @path's TAGs are in the cache */
68164f6c 798 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
3fca8422 799 const char *t, *v;
6bd8b7a7 800
3fca8422
KZ
801 if (mnt_fs_get_tag(fs, &t, &v))
802 continue;
803
804 if (mnt_cache_device_has_tag(tb->cache, cn, t, v))
805 return fs;
806 }
ba7232a1 807 } else if (rc < 0 && errno == EACCES) {
d58b3157 808 /* @path is inaccessible, try evaluating all TAGs in @tb
3fca8422 809 * by udev symlinks -- this could be expensive on systems
d58b3157 810 * with a huge fstab/mtab */
68164f6c 811 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
3fca8422
KZ
812 const char *t, *v, *x;
813 if (mnt_fs_get_tag(fs, &t, &v))
814 continue;
815 x = mnt_resolve_tag(t, v, tb->cache);
6699e742
KZ
816
817 /* both canonicalized, strcmp() is fine here */
818 if (x && strcmp(x, cn) == 0)
3fca8422
KZ
819 return fs;
820 }
6bd8b7a7
KZ
821 }
822 }
823
68164f6c
KZ
824 /* non-canonicalized paths in struct libmnt_table */
825 if (ntags <= mnt_table_get_nents(tb)) {
6bd8b7a7 826 mnt_reset_iter(&itr, direction);
68164f6c 827 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
c70d9d76 828 if (mnt_fs_is_netfs(fs) || mnt_fs_is_pseudofs(fs))
9dd75aa6 829 continue;
6bd8b7a7
KZ
830 p = mnt_fs_get_srcpath(fs);
831 if (p)
832 p = mnt_resolve_path(p, tb->cache);
6699e742
KZ
833
834 /* both canonicalized, strcmp() is fine here */
835 if (p && strcmp(p, cn) == 0)
6bd8b7a7
KZ
836 return fs;
837 }
838 }
839
840 return NULL;
841}
842
843
844/**
68164f6c 845 * mnt_table_find_tag:
6bd8b7a7
KZ
846 * @tb: tab pointer
847 * @tag: tag name (e.g "LABEL", "UUID", ...)
848 * @val: tag value
849 * @direction: MNT_ITER_{FORWARD,BACKWARD}
850 *
d58b3157 851 * Try to lookup an entry in the given tab, the first attempt is to lookup by @tag and
6bd8b7a7 852 * @val, for the second attempt the tag is evaluated (converted to the device
d58b3157 853 * name) and mnt_table_find_srcpath() is performed. The second attempt is not
68164f6c 854 * performed when @tb cache is not set (see mnt_table_set_cache()).
6bd8b7a7 855
192c6aad 856 * Returns: a tab entry or NULL.
6bd8b7a7 857 */
68164f6c 858struct libmnt_fs *mnt_table_find_tag(struct libmnt_table *tb, const char *tag,
6bd8b7a7
KZ
859 const char *val, int direction)
860{
68164f6c
KZ
861 struct libmnt_iter itr;
862 struct libmnt_fs *fs = NULL;
6bd8b7a7
KZ
863
864 assert(tb);
865 assert(tag);
866 assert(val);
867
7ba207e7 868 if (!tb || !tag || !*tag || !val)
6bd8b7a7 869 return NULL;
4cd271ad
KZ
870 if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
871 return NULL;
6bd8b7a7 872
3f31a959 873 DBG(TAB, mnt_debug_h(tb, "lookup by TAG: %s %s", tag, val));
6bd8b7a7
KZ
874
875 /* look up by TAG */
876 mnt_reset_iter(&itr, direction);
68164f6c 877 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
6bd8b7a7
KZ
878 if (fs->tagname && fs->tagval &&
879 strcmp(fs->tagname, tag) == 0 &&
880 strcmp(fs->tagval, val) == 0)
881 return fs;
882 }
883
884 if (tb->cache) {
885 /* look up by device name */
886 char *cn = mnt_resolve_tag(tag, val, tb->cache);
887 if (cn)
68164f6c 888 return mnt_table_find_srcpath(tb, cn, direction);
6bd8b7a7
KZ
889 }
890 return NULL;
891}
892
893/**
68164f6c 894 * mnt_table_find_source:
6bd8b7a7
KZ
895 * @tb: tab pointer
896 * @source: TAG or path
3d735589 897 * @direction: MNT_ITER_{FORWARD,BACKWARD}
6bd8b7a7 898 *
d58b3157
OO
899 * This is a high-level API for mnt_table_find_{srcpath,tag}. You needn't care
900 * about the @source format (device, LABEL, UUID, ...). This function parses
901 * the @source and calls mnt_table_find_tag() or mnt_table_find_srcpath().
6bd8b7a7 902 *
192c6aad 903 * Returns: a tab entry or NULL.
6bd8b7a7 904 */
f12aac6e
KZ
905struct libmnt_fs *mnt_table_find_source(struct libmnt_table *tb,
906 const char *source, int direction)
6bd8b7a7 907{
2c6b25f0
KZ
908 struct libmnt_fs *fs;
909 char *t = NULL, *v = NULL;
6bd8b7a7
KZ
910
911 assert(tb);
6bd8b7a7 912
f12aac6e 913 if (!tb)
6bd8b7a7 914 return NULL;
4cd271ad
KZ
915 if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
916 return NULL;
6bd8b7a7 917
7ba207e7 918 DBG(TAB, mnt_debug_h(tb, "lookup SOURCE: '%s'", source));
6bd8b7a7 919
2c6b25f0 920 if (blkid_parse_tag_string(source, &t, &v) || !mnt_valid_tagname(t))
68164f6c 921 fs = mnt_table_find_srcpath(tb, source, direction);
2c6b25f0
KZ
922 else
923 fs = mnt_table_find_tag(tb, t, v, direction);
924
925 free(t);
926 free(v);
6bd8b7a7
KZ
927
928 return fs;
929}
930
059c696f 931/**
68164f6c 932 * mnt_table_find_pair
059c696f
KZ
933 * @tb: tab pointer
934 * @source: TAG or path
935 * @target: mountpoint
936 * @direction: MNT_ITER_{FORWARD,BACKWARD}
937 *
938 * This function is implemented by mnt_fs_match_source() and
d58b3157 939 * mnt_fs_match_target() functions. It means that this is more expensive than
68164f6c 940 * others mnt_table_find_* function, because every @tab entry is fully evaluated.
059c696f
KZ
941 *
942 * Returns: a tab entry or NULL.
943 */
68164f6c 944struct libmnt_fs *mnt_table_find_pair(struct libmnt_table *tb, const char *source,
f12aac6e 945 const char *target, int direction)
059c696f 946{
68164f6c
KZ
947 struct libmnt_fs *fs = NULL;
948 struct libmnt_iter itr;
059c696f
KZ
949
950 assert(tb);
059c696f
KZ
951 assert(target);
952
7ba207e7 953 if (!tb || !target || !*target || !source || !*source)
059c696f 954 return NULL;
4cd271ad
KZ
955 if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
956 return NULL;
059c696f
KZ
957
958 DBG(TAB, mnt_debug_h(tb, "lookup SOURCE: %s TARGET: %s", source, target));
959
960 mnt_reset_iter(&itr, direction);
68164f6c 961 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
059c696f
KZ
962
963 if (mnt_fs_match_target(fs, target, tb->cache) &&
964 mnt_fs_match_source(fs, source, tb->cache))
965 return fs;
966 }
967
968 return NULL;
969}
970
677ff053
KZ
971/**
972 * mnt_table_find_devno
973 * @tb: /proc/self/mountinfo
974 * @devno: device number
975 * @direction: MNT_ITER_{FORWARD,BACKWARD}
976 *
d58b3157 977 * Note that zero could be a valid device number for the root pseudo filesystem (e.g.
677ff053
KZ
978 * tmpfs).
979 *
980 * Returns: a tab entry or NULL.
981 */
982struct libmnt_fs *mnt_table_find_devno(struct libmnt_table *tb,
983 dev_t devno, int direction)
984{
985 struct libmnt_fs *fs = NULL;
986 struct libmnt_iter itr;
987
988 assert(tb);
989
990 if (!tb)
991 return NULL;
4cd271ad
KZ
992 if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
993 return NULL;
677ff053
KZ
994
995 DBG(TAB, mnt_debug_h(tb, "lookup DEVNO: %d", (int) devno));
996
997 mnt_reset_iter(&itr, direction);
998
999 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
1000 if (mnt_fs_get_devno(fs) == devno)
1001 return fs;
1002 }
1003
1004 return NULL;
1005}
1006
5c60a0ea 1007/*
7293e97a
KZ
1008 * tb: /proc/self/mountinfo
1009 * fs: filesystem
1010 * mountflags: MS_BIND or 0
d58b3157 1011 * fsroot: fs-root that will probably be used in the mountinfo file
5c60a0ea
KZ
1012 * for @fs after mount(2)
1013 *
1014 * For btrfs subvolumes this function returns NULL, but @fsroot properly set.
1015 *
1016 * Returns: entry from @tb that will be used as a source for @fs if the @fs is
1017 * bindmount.
7293e97a
KZ
1018 *
1019 * Don't export to library API!
5c60a0ea
KZ
1020 */
1021struct libmnt_fs *mnt_table_get_fs_root(struct libmnt_table *tb,
1022 struct libmnt_fs *fs,
1023 unsigned long mountflags,
1024 char **fsroot)
1025{
1026 char *root = NULL, *mnt = NULL;
1027 const char *fstype;
1028 struct libmnt_fs *src_fs = NULL;
1029
5c60a0ea
KZ
1030 assert(fs);
1031 assert(fsroot);
1032
7ba207e7 1033 DBG(TAB, mnt_debug("lookup fs-root for '%s'", mnt_fs_get_source(fs)));
5c60a0ea
KZ
1034
1035 fstype = mnt_fs_get_fstype(fs);
1036
c4c66355 1037 if (tb && (mountflags & MS_BIND)) {
5c60a0ea 1038 const char *src, *src_root;
16b8db49 1039 char *xsrc = NULL;
5c60a0ea
KZ
1040
1041 DBG(TAB, mnt_debug("fs-root for bind"));
1042
16b8db49
KZ
1043 src = xsrc = mnt_resolve_spec(mnt_fs_get_source(fs), tb->cache);
1044 if (src)
1045 mnt = mnt_get_mountpoint(src);
1046 if (mnt)
1047 root = mnt_get_fs_root(src, mnt);
5c60a0ea 1048
16b8db49
KZ
1049 if (xsrc && !tb->cache) {
1050 free(xsrc);
1051 src = NULL;
1052 }
5c60a0ea
KZ
1053 if (!mnt)
1054 goto err;
1055
5c60a0ea
KZ
1056 src_fs = mnt_table_find_target(tb, mnt, MNT_ITER_BACKWARD);
1057 if (!src_fs) {
1058 DBG(TAB, mnt_debug("not found '%s' in mountinfo -- using default", mnt));
1059 goto dflt;
1060 }
1061
1062 /* on btrfs the subvolume is used as fs-root in
1063 * /proc/self/mountinfo, so we have to get the original subvolume
1064 * name from src_fs and prepend the subvolume name to the
1065 * fs-root path
1066 */
1067 src_root = mnt_fs_get_root(src_fs);
1068 if (src_root && !startswith(root, src_root)) {
1069 size_t sz = strlen(root) + strlen(src_root) + 1;
1070 char *tmp = malloc(sz);
1071
1072 if (!tmp)
1073 goto err;
1074 snprintf(tmp, sz, "%s%s", src_root, root);
1075 free(root);
1076 root = tmp;
1077 }
1078 }
1079
1080 /*
1081 * btrfs-subvolume mount -- get subvolume name and use it as a root-fs path
1082 */
1083 else if (fstype && !strcmp(fstype, "btrfs")) {
1084 char *vol = NULL, *p;
1085 size_t sz, volsz = 0;
1086
1087 if (mnt_fs_get_option(fs, "subvol", &vol, &volsz))
1088 goto dflt;
1089
1090 DBG(TAB, mnt_debug("setting FS root: btrfs subvol"));
1091
1092 sz = volsz;
1093 if (*vol != '/')
1094 sz++;
1095 root = malloc(sz + 1);
1096 if (!root)
1097 goto err;
1098 p = root;
1099 if (*vol != '/')
1100 *p++ = '/';
1101 memcpy(p, vol, volsz);
1102 *(root + sz) = '\0';
1103 }
1104dflt:
1105 if (!root) {
1106 root = strdup("/");
1107 if (!root)
1108 goto err;
1109 }
1110 *fsroot = root;
1111
1112 DBG(TAB, mnt_debug("FS root result: %s", root));
1113
1114 free(mnt);
1115 return src_fs;
1116err:
1117 free(root);
1118 free(mnt);
1119 return NULL;
1120}
1121
7293e97a
KZ
1122static int is_mountinfo(struct libmnt_table *tb)
1123{
1124 struct libmnt_fs *fs;
1125
1126 if (!tb)
1127 return 0;
1128
1129 fs = list_first_entry(&tb->ents, struct libmnt_fs, ents);
1130 if (fs && mnt_fs_is_kernel(fs) && mnt_fs_get_root(fs))
1131 return 1;
1132
1133 return 0;
1134}
1135
5c60a0ea 1136/**
d58b3157 1137 * mnt_table_is_fs__mounted:
5c60a0ea
KZ
1138 * @tb: /proc/self/mountinfo file
1139 * @fstab_fs: /etc/fstab entry
1140 *
975e14bd 1141 * Checks if the @fstab_fs entry is already in the @tb table. The "swap" is
d58b3157 1142 * ignored. This function explicitly compares the source, target and root of the
975e14bd
KZ
1143 * filesystems.
1144 *
1145 * Note that source and target are canonicalized only if a cache for @tb is
1146 * defined (see mnt_table_set_cache()). The target canonicalization may
d58b3157 1147 * trigger automount on autofs mountpoints!
975e14bd
KZ
1148 *
1149 * Don't use it if you want to know if a device is mounted, just use
d58b3157 1150 * mnt_table_find_source() on the device.
975e14bd
KZ
1151 *
1152 * This function is designed mostly for "mount -a".
5c60a0ea 1153 *
5c60a0ea
KZ
1154 * Returns: 0 or 1
1155 */
1156int mnt_table_is_fs_mounted(struct libmnt_table *tb, struct libmnt_fs *fstab_fs)
1157{
449a7646
KZ
1158 struct libmnt_iter itr;
1159 struct libmnt_fs *fs;
1160
5c60a0ea 1161 char *root = NULL;
975e14bd
KZ
1162 const char *src = NULL, *tgt = NULL;
1163 char *xtgt = NULL;
7293e97a 1164 int rc = 0;
d828dfdf 1165 dev_t devno = 0;
5c60a0ea
KZ
1166
1167 assert(tb);
1168 assert(fstab_fs);
1169
ae978c4d
KZ
1170 DBG(FS, mnt_debug_h(fstab_fs, "is FS mounted? [target=%s]",
1171 mnt_fs_get_target(fstab_fs)));
1172
1173 if (mnt_fs_is_swaparea(fstab_fs) || mnt_table_get_nents(tb) == 0) {
1174 DBG(FS, mnt_debug_h(fstab_fs, "- ignore (swap or no data)"));
5c60a0ea 1175 return 0;
ae978c4d 1176 }
5c60a0ea 1177
7293e97a
KZ
1178 if (is_mountinfo(tb)) {
1179 /* @tb is mountinfo, so we can try to use fs-roots */
c9f63764 1180 struct libmnt_fs *rootfs;
7293e97a 1181 int flags = 0;
5c60a0ea 1182
7293e97a
KZ
1183 if (mnt_fs_get_option(fstab_fs, "bind", NULL, NULL) == 0)
1184 flags = MS_BIND;
1185
c9f63764
SK
1186 rootfs = mnt_table_get_fs_root(tb, fstab_fs, flags, &root);
1187 if (rootfs)
1188 src = mnt_fs_get_srcpath(rootfs);
7293e97a
KZ
1189 }
1190
975e14bd 1191 if (!src)
14f66ad6 1192 src = mnt_fs_get_source(fstab_fs);
5c60a0ea 1193
975e14bd
KZ
1194 if (src && tb->cache && !mnt_fs_is_pseudofs(fstab_fs))
1195 src = mnt_resolve_spec(src, tb->cache);
1196
d828dfdf
KZ
1197 if (src && root) {
1198 struct stat st;
1199
1200 devno = mnt_fs_get_devno(fstab_fs);
1201 if (!devno && stat(src, &st) == 0 && S_ISBLK(st.st_mode))
1202 devno = st.st_rdev;
1203 }
1204
975e14bd 1205 tgt = mnt_fs_get_target(fstab_fs);
5c60a0ea 1206
ae978c4d
KZ
1207 if (!tgt || !src) {
1208 DBG(FS, mnt_debug_h(fstab_fs, "- ignore (no source/target)"));
449a7646 1209 goto done;
ae978c4d 1210 }
449a7646 1211 mnt_reset_iter(&itr, MNT_ITER_FORWARD);
5c60a0ea 1212
449a7646 1213 while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
975e14bd 1214
d828dfdf
KZ
1215 int eq = mnt_fs_streq_srcpath(fs, src);
1216
1217 if (!eq && devno && mnt_fs_get_devno(fs) == devno)
1218 eq = 1;
1219
1220 if (!eq) {
b2cbe99f
KZ
1221 /* The source does not match. Maybe the source is a loop
1222 * device backing file.
1223 */
1224 uint64_t offset = 0;
1225 char *val;
1226 size_t len;
1227 int flags;
1228
1229 if (!mnt_fs_is_kernel(fs) ||
1230 !mnt_fs_get_srcpath(fs) ||
1231 !startswith(mnt_fs_get_srcpath(fs), "/dev/loop"))
1232 continue; /* does not look like loopdev */
1233
1234 if (mnt_fs_get_option(fstab_fs, "offset", &val, &len) == 0 &&
1235 mnt_parse_offset(val, len, &offset)) {
1236 DBG(FS, mnt_debug_h(fstab_fs, "failed to parse offset="));
1237 continue;
1238 } else
1239 flags = LOOPDEV_FL_OFFSET;
1240
1241 if (loopdev_is_used(mnt_fs_get_srcpath(fs), src, offset, flags))
1242 break;
1243 }
1244
449a7646
KZ
1245 if (root) {
1246 const char *r = mnt_fs_get_root(fs);
1247 if (!r || strcmp(r, root) != 0)
975e14bd 1248 continue;
449a7646 1249 }
5c60a0ea 1250
449a7646 1251 /*
d58b3157 1252 * Compare target, try to minimize the number of situations when we
449a7646
KZ
1253 * need to canonicalize the path to avoid readlink() on
1254 * mountpoints.
1255 */
1256 if (!xtgt) {
1257 if (mnt_fs_streq_target(fs, tgt))
5c60a0ea 1258 break;
449a7646
KZ
1259 if (tb->cache)
1260 xtgt = mnt_resolve_path(tgt, tb->cache);
5c60a0ea 1261 }
449a7646
KZ
1262 if (xtgt && mnt_fs_streq_target(fs, xtgt))
1263 break;
5c60a0ea
KZ
1264 }
1265
449a7646
KZ
1266 if (fs)
1267 rc = 1; /* success */
1268done:
5c60a0ea 1269 free(root);
b2cbe99f
KZ
1270
1271 DBG(TAB, mnt_debug_h(tb, "mnt_table_is_fs_mounted: %s [rc=%d]", src, rc));
5c60a0ea
KZ
1272 return rc;
1273}
1274
6bd8b7a7 1275#ifdef TEST_PROGRAM
dcc15ce5 1276#include "pathnames.h"
fbb3eb85 1277
68164f6c 1278static int parser_errcb(struct libmnt_table *tb, const char *filename, int line)
fbb3eb85
KZ
1279{
1280 fprintf(stderr, "%s:%d: parse error\n", filename, line);
c3b0d5b3 1281
d58b3157 1282 return 1; /* all errors are recoverable -- this is the default */
fbb3eb85
KZ
1283}
1284
cb90e24e 1285struct libmnt_table *create_table(const char *file, int comments)
6bd8b7a7 1286{
68164f6c 1287 struct libmnt_table *tb;
6bd8b7a7
KZ
1288
1289 if (!file)
1290 return NULL;
68164f6c 1291 tb = mnt_new_table();
6bd8b7a7
KZ
1292 if (!tb)
1293 goto err;
fbb3eb85 1294
cb90e24e 1295 mnt_table_enable_comments(tb, comments);
68164f6c 1296 mnt_table_set_parser_errcb(tb, parser_errcb);
fbb3eb85 1297
68164f6c 1298 if (mnt_table_parse_file(tb, file) != 0)
6bd8b7a7 1299 goto err;
6bd8b7a7
KZ
1300 return tb;
1301err:
c3b0d5b3 1302 fprintf(stderr, "%s: parsing failed\n", file);
68164f6c 1303 mnt_free_table(tb);
6bd8b7a7
KZ
1304 return NULL;
1305}
1306
68164f6c 1307int test_copy_fs(struct libmnt_test *ts, int argc, char *argv[])
6d94f2dc 1308{
68164f6c
KZ
1309 struct libmnt_table *tb;
1310 struct libmnt_fs *fs;
059c696f 1311 int rc = -1;
6d94f2dc 1312
cb90e24e 1313 tb = create_table(argv[1], FALSE);
6d94f2dc
KZ
1314 if (!tb)
1315 return -1;
1316
68164f6c 1317 fs = mnt_table_find_target(tb, "/", MNT_ITER_FORWARD);
6d94f2dc 1318 if (!fs)
059c696f 1319 goto done;
6d94f2dc
KZ
1320
1321 printf("ORIGINAL:\n");
1322 mnt_fs_print_debug(fs, stdout);
1323
309139c7 1324 fs = mnt_copy_fs(NULL, fs);
6d94f2dc 1325 if (!fs)
059c696f 1326 goto done;
6d94f2dc
KZ
1327
1328 printf("COPY:\n");
1329 mnt_fs_print_debug(fs, stdout);
1330 mnt_free_fs(fs);
059c696f
KZ
1331 rc = 0;
1332done:
68164f6c 1333 mnt_free_table(tb);
059c696f 1334 return rc;
6d94f2dc
KZ
1335}
1336
68164f6c 1337int test_parse(struct libmnt_test *ts, int argc, char *argv[])
6bd8b7a7 1338{
68164f6c
KZ
1339 struct libmnt_table *tb = NULL;
1340 struct libmnt_iter *itr = NULL;
1341 struct libmnt_fs *fs;
059c696f 1342 int rc = -1;
cb90e24e
OO
1343 int parse_comments = FALSE;
1344
1345 if (argc == 3 && !strcmp(argv[2], "--comments"))
1346 parse_comments = TRUE;
6bd8b7a7 1347
cb90e24e 1348 tb = create_table(argv[1], parse_comments);
6bd8b7a7
KZ
1349 if (!tb)
1350 return -1;
1351
efe73c3e
KZ
1352 itr = mnt_new_iter(MNT_ITER_FORWARD);
1353 if (!itr)
059c696f 1354 goto done;
fbb3eb85 1355
cb90e24e
OO
1356 if (mnt_table_get_intro_comment(tb))
1357 fprintf(stdout, "Initial comment:\n\"%s\"\n",
1358 mnt_table_get_intro_comment(tb));
1359
68164f6c 1360 while(mnt_table_next_fs(tb, itr, &fs) == 0)
efe73c3e 1361 mnt_fs_print_debug(fs, stdout);
cb90e24e 1362
3035ba93 1363 if (mnt_table_get_trailing_comment(tb))
cb90e24e 1364 fprintf(stdout, "Trailing comment:\n\"%s\"\n",
3035ba93 1365 mnt_table_get_trailing_comment(tb));
059c696f
KZ
1366 rc = 0;
1367done:
efe73c3e 1368 mnt_free_iter(itr);
68164f6c 1369 mnt_free_table(tb);
059c696f 1370 return rc;
6bd8b7a7
KZ
1371}
1372
68164f6c 1373int test_find(struct libmnt_test *ts, int argc, char *argv[], int dr)
6bd8b7a7 1374{
68164f6c
KZ
1375 struct libmnt_table *tb;
1376 struct libmnt_fs *fs = NULL;
1377 struct libmnt_cache *mpc = NULL;
6bd8b7a7 1378 const char *file, *find, *what;
059c696f 1379 int rc = -1;
6bd8b7a7
KZ
1380
1381 if (argc != 4) {
1382 fprintf(stderr, "try --help\n");
059c696f 1383 return -EINVAL;
6bd8b7a7
KZ
1384 }
1385
1386 file = argv[1], find = argv[2], what = argv[3];
1387
cb90e24e 1388 tb = create_table(file, FALSE);
6bd8b7a7 1389 if (!tb)
059c696f 1390 goto done;
6bd8b7a7
KZ
1391
1392 /* create a cache for canonicalized paths */
1393 mpc = mnt_new_cache();
1394 if (!mpc)
059c696f 1395 goto done;
68164f6c 1396 mnt_table_set_cache(tb, mpc);
6bd8b7a7
KZ
1397
1398 if (strcasecmp(find, "source") == 0)
68164f6c 1399 fs = mnt_table_find_source(tb, what, dr);
6bd8b7a7 1400 else if (strcasecmp(find, "target") == 0)
68164f6c 1401 fs = mnt_table_find_target(tb, what, dr);
6bd8b7a7
KZ
1402
1403 if (!fs)
1404 fprintf(stderr, "%s: not found %s '%s'\n", file, find, what);
1405 else {
5e31c2c8 1406 mnt_fs_print_debug(fs, stdout);
059c696f 1407 rc = 0;
6bd8b7a7 1408 }
059c696f 1409done:
68164f6c 1410 mnt_free_table(tb);
6bd8b7a7 1411 mnt_free_cache(mpc);
059c696f 1412 return rc;
6bd8b7a7
KZ
1413}
1414
68164f6c 1415int test_find_bw(struct libmnt_test *ts, int argc, char *argv[])
6bd8b7a7
KZ
1416{
1417 return test_find(ts, argc, argv, MNT_ITER_BACKWARD);
1418}
1419
68164f6c 1420int test_find_fw(struct libmnt_test *ts, int argc, char *argv[])
6bd8b7a7
KZ
1421{
1422 return test_find(ts, argc, argv, MNT_ITER_FORWARD);
1423}
1424
68164f6c 1425int test_find_pair(struct libmnt_test *ts, int argc, char *argv[])
059c696f 1426{
68164f6c
KZ
1427 struct libmnt_table *tb;
1428 struct libmnt_fs *fs;
975e14bd 1429 struct libmnt_cache *mpc = NULL;
059c696f
KZ
1430 int rc = -1;
1431
cb90e24e 1432 tb = create_table(argv[1], FALSE);
059c696f
KZ
1433 if (!tb)
1434 return -1;
975e14bd
KZ
1435 mpc = mnt_new_cache();
1436 if (!mpc)
1437 goto done;
1438 mnt_table_set_cache(tb, mpc);
059c696f 1439
68164f6c 1440 fs = mnt_table_find_pair(tb, argv[2], argv[3], MNT_ITER_FORWARD);
059c696f
KZ
1441 if (!fs)
1442 goto done;
1443
1444 mnt_fs_print_debug(fs, stdout);
1445 rc = 0;
1446done:
68164f6c 1447 mnt_free_table(tb);
975e14bd 1448 mnt_free_cache(mpc);
059c696f
KZ
1449 return rc;
1450}
1451
dcc15ce5
KZ
1452int test_find_mountpoint(struct libmnt_test *ts, int argc, char *argv[])
1453{
1454 struct libmnt_table *tb;
1455 struct libmnt_fs *fs;
1456 struct libmnt_cache *mpc = NULL;
1457 int rc = -1;
1458
1459 tb = mnt_new_table_from_file(_PATH_PROC_MOUNTINFO);
1460 if (!tb)
1461 return -1;
1462 mpc = mnt_new_cache();
1463 if (!mpc)
1464 goto done;
1465 mnt_table_set_cache(tb, mpc);
1466
1467 fs = mnt_table_find_mountpoint(tb, argv[1], MNT_ITER_BACKWARD);
1468 if (!fs)
1469 goto done;
1470
1471 mnt_fs_print_debug(fs, stdout);
1472 rc = 0;
1473done:
1474 mnt_free_table(tb);
1475 mnt_free_cache(mpc);
1476 return rc;
1477}
1478
5c60a0ea
KZ
1479static int test_is_mounted(struct libmnt_test *ts, int argc, char *argv[])
1480{
1481 struct libmnt_table *tb = NULL, *fstab = NULL;
1482 struct libmnt_fs *fs;
1483 struct libmnt_iter *itr = NULL;
975e14bd 1484 struct libmnt_cache *mpc = NULL;
5c60a0ea
KZ
1485 int rc;
1486
1487 tb = mnt_new_table_from_file("/proc/self/mountinfo");
1488 if (!tb) {
1489 fprintf(stderr, "failed to parse mountinfo\n");
1490 return -1;
1491 }
1492
cb90e24e 1493 fstab = create_table(argv[1], FALSE);
5c60a0ea
KZ
1494 if (!fstab)
1495 goto done;
1496
1497 itr = mnt_new_iter(MNT_ITER_FORWARD);
1498 if (!itr)
1499 goto done;
1500
975e14bd
KZ
1501 mpc = mnt_new_cache();
1502 if (!mpc)
1503 goto done;
1504 mnt_table_set_cache(tb, mpc);
1505
5c60a0ea
KZ
1506 while(mnt_table_next_fs(fstab, itr, &fs) == 0) {
1507 if (mnt_table_is_fs_mounted(tb, fs))
1508 printf("%s already mounted on %s\n",
1509 mnt_fs_get_source(fs),
1510 mnt_fs_get_target(fs));
1511 else
1512 printf("%s not mounted on %s\n",
1513 mnt_fs_get_source(fs),
1514 mnt_fs_get_target(fs));
1515 }
1516
1517 rc = 0;
1518done:
1519 mnt_free_table(tb);
1520 mnt_free_table(fstab);
975e14bd 1521 mnt_free_cache(mpc);
5c60a0ea
KZ
1522 mnt_free_iter(itr);
1523 return rc;
1524}
1525
6bd8b7a7
KZ
1526int main(int argc, char *argv[])
1527{
68164f6c 1528 struct libmnt_test tss[] = {
cb90e24e 1529 { "--parse", test_parse, "<file> [--comments] parse and print tab" },
6bd8b7a7
KZ
1530 { "--find-forward", test_find_fw, "<file> <source|target> <string>" },
1531 { "--find-backward", test_find_bw, "<file> <source|target> <string>" },
059c696f 1532 { "--find-pair", test_find_pair, "<file> <source> <target>" },
dcc15ce5 1533 { "--find-mountpoint", test_find_mountpoint, "<path>" },
6d94f2dc 1534 { "--copy-fs", test_copy_fs, "<file> copy root FS from the file" },
5c60a0ea 1535 { "--is-mounted", test_is_mounted, "<fstab> check what from <file> are already mounted" },
6bd8b7a7
KZ
1536 { NULL }
1537 };
1538
1539 return mnt_run_test(tss, argc, argv);
1540}
1541
1542#endif /* TEST_PROGRAM */