]>
Commit | Line | Data |
---|---|---|
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 | 60 | struct 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 | 82 | int 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 | */ | |
105 | void 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 | 124 | int 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 | */ | |
156 | void 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 | */ | |
169 | const 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 | */ | |
184 | int 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 | */ | |
210 | int 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 | 224 | const 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 | 238 | int 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 | 264 | int 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 | 288 | int 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 | 303 | struct 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 | 318 | int 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 | 341 | int 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 | 371 | int 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 |
412 | int 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 | 487 | int 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 |
521 | int 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 | 557 | int 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 | */ | |
583 | struct 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 | 632 | struct 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 | 706 | struct 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 | 813 | struct 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 |
860 | struct 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 | 899 | struct 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 | */ | |
937 | struct 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 | */ |
976 | struct 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 | } | |
1059 | dflt: | |
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; | |
1071 | err: | |
1072 | free(root); | |
1073 | free(mnt); | |
1074 | return NULL; | |
1075 | } | |
1076 | ||
7293e97a KZ |
1077 | static 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 | */ | |
1111 | int 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 */ | |
1223 | done: | |
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 | 1233 | static 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 | 1240 | struct 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; |
1256 | err: | |
c3b0d5b3 | 1257 | fprintf(stderr, "%s: parsing failed\n", file); |
68164f6c | 1258 | mnt_free_table(tb); |
6bd8b7a7 KZ |
1259 | return NULL; |
1260 | } | |
1261 | ||
68164f6c | 1262 | int 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; |
1287 | done: | |
68164f6c | 1288 | mnt_free_table(tb); |
059c696f | 1289 | return rc; |
6d94f2dc KZ |
1290 | } |
1291 | ||
68164f6c | 1292 | int 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; |
1322 | done: | |
efe73c3e | 1323 | mnt_free_iter(itr); |
68164f6c | 1324 | mnt_free_table(tb); |
059c696f | 1325 | return rc; |
6bd8b7a7 KZ |
1326 | } |
1327 | ||
68164f6c | 1328 | int 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 | 1364 | done: |
68164f6c | 1365 | mnt_free_table(tb); |
6bd8b7a7 | 1366 | mnt_free_cache(mpc); |
059c696f | 1367 | return rc; |
6bd8b7a7 KZ |
1368 | } |
1369 | ||
68164f6c | 1370 | int 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 | 1375 | int 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 | 1380 | int 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; | |
1401 | done: | |
68164f6c | 1402 | mnt_free_table(tb); |
975e14bd | 1403 | mnt_free_cache(mpc); |
059c696f KZ |
1404 | return rc; |
1405 | } | |
1406 | ||
dcc15ce5 KZ |
1407 | int 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; | |
1428 | done: | |
1429 | mnt_free_table(tb); | |
1430 | mnt_free_cache(mpc); | |
1431 | return rc; | |
1432 | } | |
1433 | ||
5c60a0ea KZ |
1434 | static 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; | |
1473 | done: | |
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 |
1481 | int 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 */ |