]>
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 | /** | |
9 | * SECTION: tab | |
3d735589 | 10 | * @title: FS container |
192c6aad KZ |
11 | * @short_description: container for entries from fstab/mtab/mountinfo |
12 | * | |
6bd8b7a7 | 13 | * |
192c6aad KZ |
14 | * Note that mnt_tab_find_* functions are mount(8) compatible. These functions |
15 | * try to found an entry in more iterations where the first attempt is always | |
16 | * based on comparison with unmodified (non-canonicalized or un-evaluated) | |
17 | * paths or tags. For example fstab with two entries: | |
3d735589 KZ |
18 | * <informalexample> |
19 | * <programlisting> | |
192c6aad KZ |
20 | * LABEL=foo /foo auto rw |
21 | * /dev/foo /foo auto rw | |
3d735589 KZ |
22 | * </programlisting> |
23 | * </informalexample> | |
6bd8b7a7 | 24 | * |
192c6aad | 25 | * where both lines are used for the *same* device, then |
3d735589 KZ |
26 | * <informalexample> |
27 | * <programlisting> | |
192c6aad | 28 | * mnt_tab_find_source(tb, "/dev/foo", &fs); |
3d735589 KZ |
29 | * </programlisting> |
30 | * </informalexample> | |
192c6aad | 31 | * will returns the second line, and |
3d735589 KZ |
32 | * <informalexample> |
33 | * <programlisting> | |
192c6aad | 34 | * mnt_tab_find_source(tb, "LABEL=foo", &fs); |
3d735589 KZ |
35 | * </programlisting> |
36 | * </informalexample> | |
192c6aad | 37 | * will returns the first entry, and |
3d735589 KZ |
38 | * <informalexample> |
39 | * <programlisting> | |
40 | * mnt_tab_find_source(tb, "UUID=anyuuid", &fs); | |
41 | * </programlisting> | |
42 | * </informalexample> | |
192c6aad | 43 | * will returns the first entry (if UUID matches with the device). |
6bd8b7a7 KZ |
44 | */ |
45 | ||
46 | #include <string.h> | |
47 | #include <stdlib.h> | |
48 | #include <ctype.h> | |
3fca8422 | 49 | #include <errno.h> |
6bd8b7a7 KZ |
50 | #include <limits.h> |
51 | #include <sys/types.h> | |
52 | #include <sys/stat.h> | |
53 | #include <unistd.h> | |
8e368761 | 54 | #include <blkid.h> |
6bd8b7a7 KZ |
55 | |
56 | #include "nls.h" | |
57 | #include "mountP.h" | |
4951f9b3 | 58 | #include "c.h" |
6bd8b7a7 KZ |
59 | |
60 | /** | |
61 | * mnt_new_tab: | |
6bd8b7a7 KZ |
62 | * |
63 | * The tab is a container for mnt_fs entries that usually represents a fstab, | |
64 | * mtab or mountinfo file from your system. | |
65 | * | |
9ed7507c | 66 | * See also mnt_tab_parse_file(). |
6bd8b7a7 | 67 | * |
192c6aad | 68 | * Returns: newly allocated tab struct. |
6bd8b7a7 | 69 | */ |
9ed7507c | 70 | mnt_tab *mnt_new_tab(void) |
6bd8b7a7 KZ |
71 | { |
72 | mnt_tab *tb = NULL; | |
73 | ||
74 | tb = calloc(1, sizeof(struct _mnt_tab)); | |
75 | if (!tb) | |
9ed7507c KZ |
76 | return NULL; |
77 | ||
78 | DBG(DEBUG_TAB, fprintf(stderr, "libmount: new tab %p\n", tb)); | |
6bd8b7a7 | 79 | |
6bd8b7a7 KZ |
80 | INIT_LIST_HEAD(&tb->ents); |
81 | return tb; | |
6bd8b7a7 KZ |
82 | } |
83 | ||
84 | /** | |
85 | * mnt_free_tab: | |
3d735589 | 86 | * @tb: tab pointer |
6bd8b7a7 KZ |
87 | * |
88 | * Deallocates tab struct and all entries. | |
89 | */ | |
90 | void mnt_free_tab(mnt_tab *tb) | |
91 | { | |
92 | if (!tb) | |
93 | return; | |
6bd8b7a7 KZ |
94 | |
95 | while (!list_empty(&tb->ents)) { | |
96 | mnt_fs *fs = list_entry(tb->ents.next, mnt_fs, ents); | |
97 | mnt_free_fs(fs); | |
98 | } | |
99 | ||
100 | free(tb); | |
101 | } | |
102 | ||
103 | /** | |
104 | * mnt_tab_get_nents: | |
105 | * @tb: pointer to tab | |
106 | * | |
192c6aad | 107 | * Returns: number of valid entries in tab. |
6bd8b7a7 KZ |
108 | */ |
109 | int mnt_tab_get_nents(mnt_tab *tb) | |
110 | { | |
111 | assert(tb); | |
112 | return tb ? tb->nents : 0; | |
113 | } | |
114 | ||
115 | /** | |
116 | * mnt_tab_set_cache: | |
117 | * @tb: pointer to tab | |
118 | * @mpc: pointer to mnt_cache instance | |
119 | * | |
120 | * Setups a cache for canonicalized paths and evaluated tags (LABEL/UUID). The | |
121 | * cache is recommended for mnt_tab_find_*() functions. | |
122 | * | |
123 | * The cache could be shared between more tabs. Be careful when you share the | |
124 | * same cache between more threads -- currently the cache does not provide any | |
125 | * locking method. | |
126 | * | |
127 | * See also mnt_new_cache(). | |
128 | * | |
59ae0ddd | 129 | * Returns: 0 on success or negative number in case of error. |
6bd8b7a7 KZ |
130 | */ |
131 | int mnt_tab_set_cache(mnt_tab *tb, mnt_cache *mpc) | |
132 | { | |
133 | assert(tb); | |
134 | if (!tb) | |
59ae0ddd | 135 | return -EINVAL; |
6bd8b7a7 KZ |
136 | tb->cache = mpc; |
137 | return 0; | |
138 | } | |
139 | ||
140 | /** | |
141 | * mnt_tab_get_cache: | |
142 | * @tb: pointer to tab | |
143 | * | |
192c6aad | 144 | * Returns: pointer to mnt_cache instance or NULL. |
6bd8b7a7 KZ |
145 | */ |
146 | mnt_cache *mnt_tab_get_cache(mnt_tab *tb) | |
147 | { | |
148 | assert(tb); | |
149 | return tb ? tb->cache : NULL; | |
150 | } | |
151 | ||
6bd8b7a7 KZ |
152 | /** |
153 | * mnt_tab_add_fs: | |
154 | * @tb: tab pointer | |
155 | * @fs: new entry | |
156 | * | |
157 | * Adds a new entry to tab. | |
158 | * | |
59ae0ddd | 159 | * Returns: 0 on success or negative number in case of error. |
6bd8b7a7 KZ |
160 | */ |
161 | int mnt_tab_add_fs(mnt_tab *tb, mnt_fs *fs) | |
162 | { | |
163 | assert(tb); | |
164 | assert(fs); | |
165 | ||
166 | if (!tb || !fs) | |
59ae0ddd | 167 | return -EINVAL; |
6bd8b7a7 KZ |
168 | |
169 | list_add_tail(&fs->ents, &tb->ents); | |
170 | ||
171 | DBG(DEBUG_TAB, fprintf(stderr, | |
9ed7507c KZ |
172 | "libmount: tab %p: add entry: %s %s\n", |
173 | tb, mnt_fs_get_source(fs), | |
6bd8b7a7 KZ |
174 | mnt_fs_get_target(fs))); |
175 | ||
911238af | 176 | tb->nents++; |
6bd8b7a7 KZ |
177 | return 0; |
178 | } | |
179 | ||
180 | /** | |
181 | * mnt_tab_remove_fs: | |
182 | * @tb: tab pointer | |
183 | * @fs: new entry | |
184 | * | |
59ae0ddd | 185 | * Returns: 0 on success or negative number in case of error. |
6bd8b7a7 KZ |
186 | */ |
187 | int mnt_tab_remove_fs(mnt_tab *tb, mnt_fs *fs) | |
188 | { | |
189 | assert(tb); | |
190 | assert(fs); | |
191 | ||
192 | if (!tb || !fs) | |
59ae0ddd | 193 | return -EINVAL; |
6bd8b7a7 | 194 | list_del(&fs->ents); |
911238af | 195 | tb->nents--; |
6bd8b7a7 KZ |
196 | return 0; |
197 | } | |
198 | ||
26b4f9e4 KZ |
199 | /** |
200 | * mnt_tab_get_root_fs: | |
201 | * @tb: mountinfo file (/proc/self/mountinfo) | |
202 | * @root: returns pointer to the root filesystem (/) | |
203 | * | |
204 | * Returns: 0 on success or -1 case of error. | |
205 | */ | |
206 | int mnt_tab_get_root_fs(mnt_tab *tb, mnt_fs **root) | |
207 | { | |
208 | mnt_iter itr; | |
209 | mnt_fs *fs; | |
210 | int root_id = 0; | |
211 | ||
212 | assert(tb); | |
213 | assert(root); | |
214 | ||
215 | if (!tb || !root) | |
59ae0ddd | 216 | return -EINVAL; |
26b4f9e4 | 217 | |
9ed7507c | 218 | DBG(DEBUG_TAB, fprintf(stderr, "libmount: tab %p: lookup root fs\n", tb)); |
20aae9d3 | 219 | |
26b4f9e4 KZ |
220 | mnt_reset_iter(&itr, MNT_ITER_FORWARD); |
221 | while(mnt_tab_next_fs(tb, &itr, &fs) == 0) { | |
222 | int id = mnt_fs_get_parent_id(fs); | |
223 | if (!id) | |
224 | break; /* @tab is not mountinfo file? */ | |
225 | ||
226 | if (!*root || id < root_id) { | |
227 | *root = fs; | |
228 | root_id = id; | |
229 | } | |
230 | } | |
231 | ||
59ae0ddd | 232 | return root_id ? 0 : -EINVAL; |
26b4f9e4 KZ |
233 | } |
234 | ||
235 | /** | |
236 | * mnt_tab_next_child_fs: | |
237 | * @tb: mountinfo file (/proc/self/mountinfo) | |
3d735589 | 238 | * @itr: iterator |
26b4f9e4 KZ |
239 | * @parent: parental FS |
240 | * @chld: returns the next child filesystem | |
241 | * | |
242 | * Note that filesystems are returned in the order how was mounted (according to | |
243 | * IDs in /proc/self/mountinfo). | |
244 | * | |
59ae0ddd | 245 | * Returns: 0 on success, negative number in case of error or 1 at end of list. |
26b4f9e4 KZ |
246 | */ |
247 | int mnt_tab_next_child_fs(mnt_tab *tb, mnt_iter *itr, | |
248 | mnt_fs *parent, mnt_fs **chld) | |
249 | { | |
250 | mnt_fs *fs; | |
251 | int parent_id, lastchld_id = 0, chld_id = 0; | |
252 | ||
253 | if (!tb || !itr || !parent) | |
59ae0ddd | 254 | return -EINVAL; |
26b4f9e4 | 255 | |
20aae9d3 | 256 | DBG(DEBUG_TAB, fprintf(stderr, |
9ed7507c KZ |
257 | "libmount: tab %p: lookup next child of %s\n", |
258 | tb, mnt_fs_get_target(parent))); | |
20aae9d3 | 259 | |
26b4f9e4 KZ |
260 | parent_id = mnt_fs_get_id(parent); |
261 | if (!parent_id) | |
59ae0ddd | 262 | return -EINVAL; |
26b4f9e4 KZ |
263 | |
264 | /* get ID of the previously returned child */ | |
265 | if (itr->head && itr->p != itr->head) { | |
266 | MNT_ITER_ITERATE(itr, fs, struct _mnt_fs, ents); | |
267 | lastchld_id = mnt_fs_get_id(fs); | |
268 | } | |
269 | ||
270 | *chld = NULL; | |
271 | ||
272 | mnt_reset_iter(itr, MNT_ITER_FORWARD); | |
273 | while(mnt_tab_next_fs(tb, itr, &fs) == 0) { | |
274 | int id; | |
275 | ||
276 | if (mnt_fs_get_parent_id(fs) != parent_id) | |
277 | continue; | |
278 | ||
279 | id = mnt_fs_get_id(fs); | |
280 | ||
281 | if ((!lastchld_id || id > lastchld_id) && | |
282 | (!*chld || id < chld_id)) { | |
283 | *chld = fs; | |
284 | chld_id = id; | |
285 | } | |
286 | } | |
287 | ||
288 | if (!chld_id) | |
289 | return 1; /* end of iterator */ | |
290 | ||
291 | /* set the iterator to the @chld for the next call */ | |
292 | mnt_tab_set_iter(tb, itr, *chld); | |
293 | ||
294 | return 0; | |
295 | } | |
296 | ||
6bd8b7a7 KZ |
297 | /** |
298 | * mnt_tab_next_fs: | |
299 | * @tb: tab pointer | |
300 | * @itr: iterator | |
301 | * @fs: returns the next tab entry | |
302 | * | |
59ae0ddd | 303 | * Returns: 0 on success, negative number in case of error or 1 at end of list. |
6bd8b7a7 KZ |
304 | * |
305 | * Example (list all mountpoints from fstab in backward order): | |
3d735589 KZ |
306 | * <informalexample> |
307 | * <programlisting> | |
6bd8b7a7 KZ |
308 | * mnt_fs *fs; |
309 | * mnt_tab *tb = mnt_new_tab("/etc/fstab"); | |
310 | * mnt_iter *itr = mnt_new_iter(MNT_ITER_BACKWARD); | |
311 | * | |
312 | * mnt_tab_parse_file(tb); | |
313 | * | |
314 | * while(mnt_tab_next_fs(tb, itr, &fs) == 0) { | |
315 | * const char *dir = mnt_fs_get_target(fs); | |
316 | * printf("mount point: %s\n", dir); | |
317 | * } | |
318 | * mnt_free_tab(fi); | |
3d735589 KZ |
319 | * </programlisting> |
320 | * </informalexample> | |
6bd8b7a7 KZ |
321 | */ |
322 | int mnt_tab_next_fs(mnt_tab *tb, mnt_iter *itr, mnt_fs **fs) | |
323 | { | |
59ae0ddd | 324 | int rc = 1; |
3fca8422 | 325 | |
6bd8b7a7 KZ |
326 | assert(tb); |
327 | assert(itr); | |
328 | assert(fs); | |
329 | ||
330 | if (!tb || !itr || !fs) | |
59ae0ddd | 331 | return -EINVAL; |
0532ba1d KZ |
332 | *fs = NULL; |
333 | ||
6bd8b7a7 KZ |
334 | if (!itr->head) |
335 | MNT_ITER_INIT(itr, &tb->ents); | |
336 | if (itr->p != itr->head) { | |
337 | MNT_ITER_ITERATE(itr, *fs, struct _mnt_fs, ents); | |
3fca8422 | 338 | rc = 0; |
6bd8b7a7 KZ |
339 | } |
340 | ||
3fca8422 KZ |
341 | return rc; |
342 | } | |
343 | ||
344 | /** | |
345 | * mnt_tab_find_next_fs: | |
346 | * @tb: table | |
347 | * @itr: iterator | |
348 | * @match_func: function returns 1 or 0 | |
3d735589 | 349 | * @userdata: extra data for match_func |
3fca8422 KZ |
350 | * @fs: returns pointer to the next matching table entry |
351 | * | |
352 | * This function allows search in @tb. | |
353 | * | |
59ae0ddd | 354 | * Returns: negative number in case of error, 1 at end of table or 0 o success. |
3fca8422 KZ |
355 | */ |
356 | int mnt_tab_find_next_fs(mnt_tab *tb, mnt_iter *itr, | |
357 | int (*match_func)(mnt_fs *, void *), void *userdata, | |
358 | mnt_fs **fs) | |
359 | { | |
360 | if (!tb || !itr || !fs || !match_func) | |
59ae0ddd | 361 | return -EINVAL; |
3fca8422 | 362 | |
20aae9d3 | 363 | DBG(DEBUG_TAB, fprintf(stderr, |
9ed7507c | 364 | "libmount: tab %p: lookup next fs\n", tb)); |
20aae9d3 | 365 | |
3fca8422 KZ |
366 | if (!itr->head) |
367 | MNT_ITER_INIT(itr, &tb->ents); | |
368 | ||
369 | do { | |
370 | if (itr->p != itr->head) | |
371 | MNT_ITER_ITERATE(itr, *fs, struct _mnt_fs, ents); | |
372 | else | |
373 | break; /* end */ | |
374 | ||
3fca8422 KZ |
375 | if (match_func(*fs, userdata)) |
376 | return 0; | |
377 | } while(1); | |
378 | ||
26b4f9e4 | 379 | *fs = NULL; |
6bd8b7a7 KZ |
380 | return 1; |
381 | } | |
382 | ||
383 | /** | |
384 | * mnt_tab_set_iter: | |
385 | * @tb: tab pointer | |
386 | * @itr: iterator | |
387 | * @fs: tab entry | |
388 | * | |
389 | * Sets @iter to the position of @fs in the file @tb. | |
390 | * | |
59ae0ddd | 391 | * Returns: 0 on success, negative number in case of error. |
6bd8b7a7 KZ |
392 | */ |
393 | int mnt_tab_set_iter(mnt_tab *tb, mnt_iter *itr, mnt_fs *fs) | |
394 | { | |
395 | assert(tb); | |
396 | assert(itr); | |
397 | assert(fs); | |
398 | ||
399 | if (!tb || !itr || !fs) | |
59ae0ddd | 400 | return -EINVAL; |
6bd8b7a7 KZ |
401 | |
402 | MNT_ITER_INIT(itr, &tb->ents); | |
403 | itr->p = &fs->ents; | |
404 | ||
405 | return 0; | |
406 | } | |
407 | ||
408 | /** | |
409 | * mnt_tab_find_target: | |
410 | * @tb: tab pointer | |
411 | * @path: mountpoint directory | |
412 | * @direction: MNT_ITER_{FORWARD,BACKWARD} | |
413 | * | |
414 | * Try to lookup an entry in given tab, possible are three iterations, first | |
415 | * with @path, second with realpath(@path) and third with realpath(@path) | |
416 | * against realpath(fs->target). The 2nd and 3rd iterations are not performed | |
417 | * when @tb cache is not set (see mnt_tab_set_cache()). | |
418 | * | |
192c6aad | 419 | * Returns: a tab entry or NULL. |
6bd8b7a7 KZ |
420 | */ |
421 | mnt_fs *mnt_tab_find_target(mnt_tab *tb, const char *path, int direction) | |
422 | { | |
423 | mnt_iter itr; | |
424 | mnt_fs *fs = NULL; | |
425 | char *cn; | |
426 | ||
427 | assert(tb); | |
428 | assert(path); | |
429 | ||
59ae0ddd KZ |
430 | if (!tb || !path) |
431 | return NULL; | |
432 | ||
6bd8b7a7 | 433 | DBG(DEBUG_TAB, fprintf(stderr, |
9ed7507c | 434 | "libmount: tab %p: lookup target: %s\n", tb, path)); |
6bd8b7a7 KZ |
435 | |
436 | /* native @target */ | |
437 | mnt_reset_iter(&itr, direction); | |
438 | while(mnt_tab_next_fs(tb, &itr, &fs) == 0) | |
439 | if (fs->target && strcmp(fs->target, path) == 0) | |
440 | return fs; | |
441 | ||
442 | if (!tb->cache || !(cn = mnt_resolve_path(path, tb->cache))) | |
443 | return NULL; | |
444 | ||
445 | /* canonicalized paths in mnt_tab */ | |
446 | mnt_reset_iter(&itr, direction); | |
447 | while(mnt_tab_next_fs(tb, &itr, &fs) == 0) { | |
448 | if (fs->target && strcmp(fs->target, cn) == 0) | |
449 | return fs; | |
450 | } | |
451 | ||
452 | /* non-canonicaled path in mnt_tab */ | |
453 | mnt_reset_iter(&itr, direction); | |
454 | while(mnt_tab_next_fs(tb, &itr, &fs) == 0) { | |
455 | char *p; | |
456 | if (!fs->target) | |
457 | continue; | |
458 | p = mnt_resolve_path(fs->target, tb->cache); | |
459 | if (strcmp(cn, p) == 0) | |
460 | return fs; | |
461 | } | |
462 | return NULL; | |
463 | } | |
464 | ||
465 | /** | |
466 | * mnt_tab_find_srcpath: | |
467 | * @tb: tab pointer | |
468 | * @path: source path (devname or dirname) | |
469 | * @direction: MNT_ITER_{FORWARD,BACKWARD} | |
470 | * | |
471 | * Try to lookup an entry in given tab, possible are four iterations, first | |
472 | * with @path, second with realpath(@path), third with tags (LABEL, UUID, ..) | |
473 | * from @path and fourth with realpath(@path) against realpath(entry->srcpath). | |
474 | * | |
475 | * The 2nd, 3rd and 4th iterations are not performed when @tb cache is not | |
476 | * set (see mnt_tab_set_cache()). | |
477 | * | |
192c6aad | 478 | * Returns: a tab entry or NULL. |
6bd8b7a7 KZ |
479 | */ |
480 | mnt_fs *mnt_tab_find_srcpath(mnt_tab *tb, const char *path, int direction) | |
481 | { | |
482 | mnt_iter itr; | |
483 | mnt_fs *fs = NULL; | |
484 | int ntags = 0; | |
485 | char *cn; | |
486 | const char *p; | |
487 | ||
488 | assert(tb); | |
489 | assert(path); | |
490 | ||
491 | DBG(DEBUG_TAB, fprintf(stderr, | |
9ed7507c | 492 | "libmount: tab %p: lookup srcpath: %s\n", tb, path)); |
6bd8b7a7 KZ |
493 | |
494 | /* native paths */ | |
495 | mnt_reset_iter(&itr, direction); | |
496 | while(mnt_tab_next_fs(tb, &itr, &fs) == 0) { | |
497 | p = mnt_fs_get_srcpath(fs); | |
498 | if (p && strcmp(p, path) == 0) | |
499 | return fs; | |
500 | if (!p) | |
501 | /* mnt_fs_get_srcpath() returs nothing, it's TAG */ | |
502 | ntags++; | |
503 | } | |
504 | ||
505 | if (!tb->cache || !(cn = mnt_resolve_path(path, tb->cache))) | |
506 | return NULL; | |
507 | ||
508 | /* canonicalized paths in mnt_tab */ | |
509 | if (ntags < mnt_tab_get_nents(tb)) { | |
510 | mnt_reset_iter(&itr, direction); | |
511 | while(mnt_tab_next_fs(tb, &itr, &fs) == 0) { | |
512 | p = mnt_fs_get_srcpath(fs); | |
513 | if (p && strcmp(p, cn) == 0) | |
514 | return fs; | |
515 | } | |
516 | } | |
517 | ||
518 | /* evaluated tag */ | |
3fca8422 | 519 | if (ntags) { |
ba7232a1 KZ |
520 | int rc = mnt_cache_read_tags(tb->cache, cn); |
521 | ||
6bd8b7a7 | 522 | mnt_reset_iter(&itr, direction); |
6bd8b7a7 | 523 | |
ba7232a1 | 524 | if (rc == 0) { |
3fca8422 KZ |
525 | /* @path's TAGs are in the cache */ |
526 | while(mnt_tab_next_fs(tb, &itr, &fs) == 0) { | |
527 | const char *t, *v; | |
6bd8b7a7 | 528 | |
3fca8422 KZ |
529 | if (mnt_fs_get_tag(fs, &t, &v)) |
530 | continue; | |
531 | ||
532 | if (mnt_cache_device_has_tag(tb->cache, cn, t, v)) | |
533 | return fs; | |
534 | } | |
ba7232a1 | 535 | } else if (rc < 0 && errno == EACCES) { |
3fca8422 KZ |
536 | /* @path is unaccessible, try evaluate all TAGs in @tb |
537 | * by udev symlinks -- this could be expensive on systems | |
538 | * with huge fstab/mtab */ | |
539 | while(mnt_tab_next_fs(tb, &itr, &fs) == 0) { | |
540 | const char *t, *v, *x; | |
541 | if (mnt_fs_get_tag(fs, &t, &v)) | |
542 | continue; | |
543 | x = mnt_resolve_tag(t, v, tb->cache); | |
544 | if (x && !strcmp(x, cn)) | |
545 | return fs; | |
546 | } | |
6bd8b7a7 KZ |
547 | } |
548 | } | |
549 | ||
550 | /* non-canonicalized paths in mnt_tab */ | |
551 | if (ntags <= mnt_tab_get_nents(tb)) { | |
552 | mnt_reset_iter(&itr, direction); | |
553 | while(mnt_tab_next_fs(tb, &itr, &fs) == 0) { | |
554 | p = mnt_fs_get_srcpath(fs); | |
555 | if (p) | |
556 | p = mnt_resolve_path(p, tb->cache); | |
557 | if (p && strcmp(cn, p) == 0) | |
558 | return fs; | |
559 | } | |
560 | } | |
561 | ||
562 | return NULL; | |
563 | } | |
564 | ||
565 | ||
566 | /** | |
567 | * mnt_tab_find_tag: | |
568 | * @tb: tab pointer | |
569 | * @tag: tag name (e.g "LABEL", "UUID", ...) | |
570 | * @val: tag value | |
571 | * @direction: MNT_ITER_{FORWARD,BACKWARD} | |
572 | * | |
573 | * Try to lookup an entry in given tab, first attempt is lookup by @tag and | |
574 | * @val, for the second attempt the tag is evaluated (converted to the device | |
575 | * name) and mnt_tab_find_srcpath() is preformed. The second attempt is not | |
576 | * performed when @tb cache is not set (see mnt_tab_set_cache()). | |
577 | ||
192c6aad | 578 | * Returns: a tab entry or NULL. |
6bd8b7a7 KZ |
579 | */ |
580 | mnt_fs *mnt_tab_find_tag(mnt_tab *tb, const char *tag, | |
581 | const char *val, int direction) | |
582 | { | |
583 | mnt_iter itr; | |
584 | mnt_fs *fs = NULL; | |
585 | ||
586 | assert(tb); | |
587 | assert(tag); | |
588 | assert(val); | |
589 | ||
590 | if (!tb || !tag || !val) | |
591 | return NULL; | |
592 | ||
593 | DBG(DEBUG_TAB, fprintf(stderr, | |
9ed7507c | 594 | "libmount: tab %p: lookup by TAG: %s %s\n", tb, tag, val)); |
6bd8b7a7 KZ |
595 | |
596 | /* look up by TAG */ | |
597 | mnt_reset_iter(&itr, direction); | |
598 | while(mnt_tab_next_fs(tb, &itr, &fs) == 0) { | |
599 | if (fs->tagname && fs->tagval && | |
600 | strcmp(fs->tagname, tag) == 0 && | |
601 | strcmp(fs->tagval, val) == 0) | |
602 | return fs; | |
603 | } | |
604 | ||
605 | if (tb->cache) { | |
606 | /* look up by device name */ | |
607 | char *cn = mnt_resolve_tag(tag, val, tb->cache); | |
608 | if (cn) | |
609 | return mnt_tab_find_srcpath(tb, cn, direction); | |
610 | } | |
611 | return NULL; | |
612 | } | |
613 | ||
614 | /** | |
615 | * mnt_tab_find_source: | |
616 | * @tb: tab pointer | |
617 | * @source: TAG or path | |
3d735589 | 618 | * @direction: MNT_ITER_{FORWARD,BACKWARD} |
6bd8b7a7 KZ |
619 | * |
620 | * This is high-level API for mnt_tab_find_{srcpath,tag}. You needn't to care | |
621 | * about @source format (device, LABEL, UUID, ...). This function parses @source | |
622 | * and calls mnt_tab_find_tag() or mnt_tab_find_srcpath(). | |
623 | * | |
192c6aad | 624 | * Returns: a tab entry or NULL. |
6bd8b7a7 KZ |
625 | */ |
626 | mnt_fs *mnt_tab_find_source(mnt_tab *tb, const char *source, int direction) | |
627 | { | |
628 | mnt_fs *fs = NULL; | |
629 | ||
630 | assert(tb); | |
631 | assert(source); | |
632 | ||
633 | if (!tb || !source) | |
634 | return NULL; | |
635 | ||
636 | DBG(DEBUG_TAB, fprintf(stderr, | |
9ed7507c | 637 | "libmount: tab %p: lookup SOURCE: %s\n", tb, source)); |
6bd8b7a7 KZ |
638 | |
639 | if (strchr(source, '=')) { | |
640 | char *tag, *val; | |
641 | ||
642 | if (blkid_parse_tag_string(source, &tag, &val) == 0) { | |
643 | ||
644 | fs = mnt_tab_find_tag(tb, tag, val, direction); | |
645 | ||
646 | free(tag); | |
647 | free(val); | |
648 | } | |
649 | } else | |
650 | fs = mnt_tab_find_srcpath(tb, source, direction); | |
651 | ||
652 | return fs; | |
653 | } | |
654 | ||
6bd8b7a7 | 655 | #ifdef TEST_PROGRAM |
fbb3eb85 KZ |
656 | |
657 | static int parser_errcb(mnt_tab *tb, const char *filename, int line, int flag) | |
658 | { | |
659 | fprintf(stderr, "%s:%d: parse error\n", filename, line); | |
660 | return 0; | |
661 | } | |
662 | ||
6bd8b7a7 KZ |
663 | mnt_tab *create_tab(const char *file) |
664 | { | |
665 | mnt_tab *tb; | |
666 | ||
667 | if (!file) | |
668 | return NULL; | |
9ed7507c | 669 | tb = mnt_new_tab(); |
6bd8b7a7 KZ |
670 | if (!tb) |
671 | goto err; | |
fbb3eb85 KZ |
672 | |
673 | mnt_tab_set_parser_errcb(tb, parser_errcb); | |
674 | ||
9ed7507c | 675 | if (mnt_tab_parse_file(tb, file) != 0) |
6bd8b7a7 | 676 | goto err; |
6bd8b7a7 KZ |
677 | return tb; |
678 | err: | |
679 | mnt_free_tab(tb); | |
680 | return NULL; | |
681 | } | |
682 | ||
6d94f2dc KZ |
683 | int test_copy_fs(struct mtest *ts, int argc, char *argv[]) |
684 | { | |
685 | mnt_tab *tb; | |
686 | mnt_fs *fs; | |
687 | ||
688 | tb = create_tab(argv[1]); | |
689 | if (!tb) | |
690 | return -1; | |
691 | ||
692 | fs = mnt_tab_find_target(tb, "/", MNT_ITER_FORWARD); | |
693 | if (!fs) | |
694 | goto err; | |
695 | ||
696 | printf("ORIGINAL:\n"); | |
697 | mnt_fs_print_debug(fs, stdout); | |
698 | ||
699 | fs = mnt_copy_fs(fs); | |
700 | if (!fs) | |
701 | goto err; | |
702 | ||
703 | printf("COPY:\n"); | |
704 | mnt_fs_print_debug(fs, stdout); | |
705 | mnt_free_fs(fs); | |
706 | err: | |
707 | mnt_free_tab(tb); | |
708 | return 0; | |
709 | } | |
710 | ||
6bd8b7a7 KZ |
711 | int test_parse(struct mtest *ts, int argc, char *argv[]) |
712 | { | |
713 | mnt_tab *tb; | |
efe73c3e KZ |
714 | mnt_iter *itr; |
715 | mnt_fs *fs; | |
6bd8b7a7 KZ |
716 | |
717 | tb = create_tab(argv[1]); | |
718 | if (!tb) | |
719 | return -1; | |
720 | ||
efe73c3e KZ |
721 | itr = mnt_new_iter(MNT_ITER_FORWARD); |
722 | if (!itr) | |
723 | goto err; | |
fbb3eb85 | 724 | |
efe73c3e KZ |
725 | while(mnt_tab_next_fs(tb, itr, &fs) == 0) |
726 | mnt_fs_print_debug(fs, stdout); | |
727 | err: | |
728 | mnt_free_iter(itr); | |
6bd8b7a7 KZ |
729 | mnt_free_tab(tb); |
730 | return 0; | |
731 | } | |
732 | ||
733 | int test_find(struct mtest *ts, int argc, char *argv[], int dr) | |
734 | { | |
735 | mnt_tab *tb; | |
736 | mnt_fs *fs = NULL; | |
737 | mnt_cache *mpc; | |
738 | const char *file, *find, *what; | |
739 | ||
740 | if (argc != 4) { | |
741 | fprintf(stderr, "try --help\n"); | |
742 | goto err; | |
743 | } | |
744 | ||
745 | file = argv[1], find = argv[2], what = argv[3]; | |
746 | ||
747 | tb = create_tab(file); | |
748 | if (!tb) | |
749 | goto err; | |
750 | ||
751 | /* create a cache for canonicalized paths */ | |
752 | mpc = mnt_new_cache(); | |
753 | if (!mpc) | |
754 | goto err; | |
755 | mnt_tab_set_cache(tb, mpc); | |
756 | ||
757 | if (strcasecmp(find, "source") == 0) | |
758 | fs = mnt_tab_find_source(tb, what, dr); | |
759 | else if (strcasecmp(find, "target") == 0) | |
760 | fs = mnt_tab_find_target(tb, what, dr); | |
761 | ||
762 | if (!fs) | |
763 | fprintf(stderr, "%s: not found %s '%s'\n", file, find, what); | |
764 | else { | |
765 | const char *s = mnt_fs_get_srcpath(fs); | |
766 | if (s) | |
767 | printf("%s", s); | |
768 | else { | |
769 | const char *tag, *val; | |
770 | mnt_fs_get_tag(fs, &tag, &val); | |
771 | printf("%s=%s", tag, val); | |
772 | } | |
773 | printf("|%s|%s\n", mnt_fs_get_target(fs), | |
774 | mnt_fs_get_optstr(fs)); | |
775 | } | |
776 | mnt_free_tab(tb); | |
777 | mnt_free_cache(mpc); | |
778 | return 0; | |
779 | err: | |
780 | return -1; | |
781 | } | |
782 | ||
783 | int test_find_bw(struct mtest *ts, int argc, char *argv[]) | |
784 | { | |
785 | return test_find(ts, argc, argv, MNT_ITER_BACKWARD); | |
786 | } | |
787 | ||
788 | int test_find_fw(struct mtest *ts, int argc, char *argv[]) | |
789 | { | |
790 | return test_find(ts, argc, argv, MNT_ITER_FORWARD); | |
791 | } | |
792 | ||
793 | int main(int argc, char *argv[]) | |
794 | { | |
795 | struct mtest tss[] = { | |
6bd8b7a7 KZ |
796 | { "--parse", test_parse, "<file> parse and print tab" }, |
797 | { "--find-forward", test_find_fw, "<file> <source|target> <string>" }, | |
798 | { "--find-backward", test_find_bw, "<file> <source|target> <string>" }, | |
6d94f2dc | 799 | { "--copy-fs", test_copy_fs, "<file> copy root FS from the file" }, |
6bd8b7a7 KZ |
800 | { NULL } |
801 | }; | |
802 | ||
803 | return mnt_run_test(tss, argc, argv); | |
804 | } | |
805 | ||
806 | #endif /* TEST_PROGRAM */ |