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