]>
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 | |
0f32f1e2 | 10 | * @title: Table of filesystems |
192c6aad KZ |
11 | * @short_description: container for entries from fstab/mtab/mountinfo |
12 | * | |
6bd8b7a7 | 13 | * |
68164f6c | 14 | * Note that mnt_table_find_* functions are mount(8) compatible. These functions |
192c6aad KZ |
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> | |
68164f6c | 28 | * mnt_table_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> | |
68164f6c | 34 | * mnt_table_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> | |
68164f6c | 40 | * mnt_table_find_source(tb, "UUID=anyuuid", &fs); |
3d735589 KZ |
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 | /** | |
68164f6c | 61 | * mnt_new_table: |
6bd8b7a7 | 62 | * |
68164f6c | 63 | * The tab is a container for struct libmnt_fs entries that usually represents a fstab, |
6bd8b7a7 KZ |
64 | * mtab or mountinfo file from your system. |
65 | * | |
68164f6c | 66 | * See also mnt_table_parse_file(). |
6bd8b7a7 | 67 | * |
192c6aad | 68 | * Returns: newly allocated tab struct. |
6bd8b7a7 | 69 | */ |
68164f6c | 70 | struct libmnt_table *mnt_new_table(void) |
6bd8b7a7 | 71 | { |
68164f6c | 72 | struct libmnt_table *tb = NULL; |
6bd8b7a7 | 73 | |
68164f6c | 74 | tb = calloc(1, sizeof(*tb)); |
6bd8b7a7 | 75 | if (!tb) |
9ed7507c KZ |
76 | return NULL; |
77 | ||
3f31a959 | 78 | DBG(TAB, mnt_debug_h(tb, "alloc")); |
6bd8b7a7 | 79 | |
6bd8b7a7 KZ |
80 | INIT_LIST_HEAD(&tb->ents); |
81 | return tb; | |
6bd8b7a7 KZ |
82 | } |
83 | ||
84 | /** | |
68164f6c | 85 | * mnt_free_table: |
3d735589 | 86 | * @tb: tab pointer |
6bd8b7a7 KZ |
87 | * |
88 | * Deallocates tab struct and all entries. | |
89 | */ | |
68164f6c | 90 | void mnt_free_table(struct libmnt_table *tb) |
6bd8b7a7 KZ |
91 | { |
92 | if (!tb) | |
93 | return; | |
6bd8b7a7 | 94 | |
3f31a959 KZ |
95 | DBG(TAB, mnt_debug_h(tb, "free")); |
96 | ||
6bd8b7a7 | 97 | while (!list_empty(&tb->ents)) { |
68164f6c KZ |
98 | struct libmnt_fs *fs = list_entry(tb->ents.next, |
99 | struct libmnt_fs, ents); | |
6bd8b7a7 KZ |
100 | mnt_free_fs(fs); |
101 | } | |
102 | ||
103 | free(tb); | |
104 | } | |
105 | ||
106 | /** | |
68164f6c | 107 | * mnt_table_get_nents: |
6bd8b7a7 KZ |
108 | * @tb: pointer to tab |
109 | * | |
192c6aad | 110 | * Returns: number of valid entries in tab. |
6bd8b7a7 | 111 | */ |
68164f6c | 112 | int mnt_table_get_nents(struct libmnt_table *tb) |
6bd8b7a7 KZ |
113 | { |
114 | assert(tb); | |
115 | return tb ? tb->nents : 0; | |
116 | } | |
117 | ||
118 | /** | |
68164f6c | 119 | * mnt_table_set_cache: |
6bd8b7a7 | 120 | * @tb: pointer to tab |
68164f6c | 121 | * @mpc: pointer to struct libmnt_cache instance |
6bd8b7a7 KZ |
122 | * |
123 | * Setups a cache for canonicalized paths and evaluated tags (LABEL/UUID). The | |
68164f6c | 124 | * cache is recommended for mnt_table_find_*() functions. |
6bd8b7a7 KZ |
125 | * |
126 | * The cache could be shared between more tabs. Be careful when you share the | |
127 | * same cache between more threads -- currently the cache does not provide any | |
128 | * locking method. | |
129 | * | |
130 | * See also mnt_new_cache(). | |
131 | * | |
59ae0ddd | 132 | * Returns: 0 on success or negative number in case of error. |
6bd8b7a7 | 133 | */ |
68164f6c | 134 | int mnt_table_set_cache(struct libmnt_table *tb, struct libmnt_cache *mpc) |
6bd8b7a7 KZ |
135 | { |
136 | assert(tb); | |
137 | if (!tb) | |
59ae0ddd | 138 | return -EINVAL; |
6bd8b7a7 KZ |
139 | tb->cache = mpc; |
140 | return 0; | |
141 | } | |
142 | ||
143 | /** | |
68164f6c | 144 | * mnt_table_get_cache: |
6bd8b7a7 KZ |
145 | * @tb: pointer to tab |
146 | * | |
68164f6c | 147 | * Returns: pointer to struct libmnt_cache instance or NULL. |
6bd8b7a7 | 148 | */ |
68164f6c | 149 | struct libmnt_cache *mnt_table_get_cache(struct libmnt_table *tb) |
6bd8b7a7 KZ |
150 | { |
151 | assert(tb); | |
152 | return tb ? tb->cache : NULL; | |
153 | } | |
154 | ||
6bd8b7a7 | 155 | /** |
68164f6c | 156 | * mnt_table_add_fs: |
6bd8b7a7 KZ |
157 | * @tb: tab pointer |
158 | * @fs: new entry | |
159 | * | |
160 | * Adds a new entry to tab. | |
161 | * | |
59ae0ddd | 162 | * Returns: 0 on success or negative number in case of error. |
6bd8b7a7 | 163 | */ |
68164f6c | 164 | int mnt_table_add_fs(struct libmnt_table *tb, struct libmnt_fs *fs) |
6bd8b7a7 KZ |
165 | { |
166 | assert(tb); | |
167 | assert(fs); | |
168 | ||
169 | if (!tb || !fs) | |
59ae0ddd | 170 | return -EINVAL; |
6bd8b7a7 KZ |
171 | |
172 | list_add_tail(&fs->ents, &tb->ents); | |
173 | ||
3f31a959 KZ |
174 | DBG(TAB, mnt_debug_h(tb, "add entry: %s %s", |
175 | mnt_fs_get_source(fs), mnt_fs_get_target(fs))); | |
911238af | 176 | tb->nents++; |
6bd8b7a7 KZ |
177 | return 0; |
178 | } | |
179 | ||
180 | /** | |
68164f6c | 181 | * mnt_table_remove_fs: |
6bd8b7a7 KZ |
182 | * @tb: tab pointer |
183 | * @fs: new entry | |
184 | * | |
59ae0ddd | 185 | * Returns: 0 on success or negative number in case of error. |
6bd8b7a7 | 186 | */ |
68164f6c | 187 | int mnt_table_remove_fs(struct libmnt_table *tb, struct libmnt_fs *fs) |
6bd8b7a7 KZ |
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 | 199 | /** |
68164f6c | 200 | * mnt_table_get_root_fs: |
26b4f9e4 KZ |
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 | */ | |
68164f6c | 206 | int mnt_table_get_root_fs(struct libmnt_table *tb, struct libmnt_fs **root) |
26b4f9e4 | 207 | { |
68164f6c KZ |
208 | struct libmnt_iter itr; |
209 | struct libmnt_fs *fs; | |
26b4f9e4 KZ |
210 | int root_id = 0; |
211 | ||
212 | assert(tb); | |
213 | assert(root); | |
214 | ||
215 | if (!tb || !root) | |
59ae0ddd | 216 | return -EINVAL; |
26b4f9e4 | 217 | |
0ccfc837 | 218 | DBG(TAB, mnt_debug_h(tb, "lookup root fs")); |
20aae9d3 | 219 | |
26b4f9e4 | 220 | mnt_reset_iter(&itr, MNT_ITER_FORWARD); |
68164f6c | 221 | while(mnt_table_next_fs(tb, &itr, &fs) == 0) { |
26b4f9e4 KZ |
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 | /** | |
68164f6c | 236 | * mnt_table_next_child_fs: |
26b4f9e4 | 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 | 246 | */ |
68164f6c KZ |
247 | int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr, |
248 | struct libmnt_fs *parent, struct libmnt_fs **chld) | |
26b4f9e4 | 249 | { |
68164f6c | 250 | struct libmnt_fs *fs; |
26b4f9e4 KZ |
251 | int parent_id, lastchld_id = 0, chld_id = 0; |
252 | ||
253 | if (!tb || !itr || !parent) | |
59ae0ddd | 254 | return -EINVAL; |
26b4f9e4 | 255 | |
3f31a959 KZ |
256 | DBG(TAB, mnt_debug_h(tb, "lookup next child of %s", |
257 | mnt_fs_get_target(parent))); | |
20aae9d3 | 258 | |
26b4f9e4 KZ |
259 | parent_id = mnt_fs_get_id(parent); |
260 | if (!parent_id) | |
59ae0ddd | 261 | return -EINVAL; |
26b4f9e4 KZ |
262 | |
263 | /* get ID of the previously returned child */ | |
264 | if (itr->head && itr->p != itr->head) { | |
68164f6c | 265 | MNT_ITER_ITERATE(itr, fs, struct libmnt_fs, ents); |
26b4f9e4 KZ |
266 | lastchld_id = mnt_fs_get_id(fs); |
267 | } | |
268 | ||
269 | *chld = NULL; | |
270 | ||
271 | mnt_reset_iter(itr, MNT_ITER_FORWARD); | |
68164f6c | 272 | while(mnt_table_next_fs(tb, itr, &fs) == 0) { |
26b4f9e4 KZ |
273 | int id; |
274 | ||
275 | if (mnt_fs_get_parent_id(fs) != parent_id) | |
276 | continue; | |
277 | ||
278 | id = mnt_fs_get_id(fs); | |
279 | ||
280 | if ((!lastchld_id || id > lastchld_id) && | |
281 | (!*chld || id < chld_id)) { | |
282 | *chld = fs; | |
283 | chld_id = id; | |
284 | } | |
285 | } | |
286 | ||
287 | if (!chld_id) | |
288 | return 1; /* end of iterator */ | |
289 | ||
290 | /* set the iterator to the @chld for the next call */ | |
68164f6c | 291 | mnt_table_set_iter(tb, itr, *chld); |
26b4f9e4 KZ |
292 | |
293 | return 0; | |
294 | } | |
295 | ||
6bd8b7a7 | 296 | /** |
68164f6c | 297 | * mnt_table_next_fs: |
6bd8b7a7 KZ |
298 | * @tb: tab pointer |
299 | * @itr: iterator | |
300 | * @fs: returns the next tab entry | |
301 | * | |
59ae0ddd | 302 | * Returns: 0 on success, negative number in case of error or 1 at end of list. |
6bd8b7a7 | 303 | * |
0f32f1e2 | 304 | * Example: |
3d735589 KZ |
305 | * <informalexample> |
306 | * <programlisting> | |
68164f6c | 307 | * while(mnt_table_next_fs(tb, itr, &fs) == 0) { |
6bd8b7a7 KZ |
308 | * const char *dir = mnt_fs_get_target(fs); |
309 | * printf("mount point: %s\n", dir); | |
310 | * } | |
68164f6c | 311 | * mnt_free_table(fi); |
3d735589 KZ |
312 | * </programlisting> |
313 | * </informalexample> | |
0f32f1e2 KZ |
314 | * |
315 | * lists all mountpoints from fstab in backward order. | |
6bd8b7a7 | 316 | */ |
68164f6c | 317 | int mnt_table_next_fs(struct libmnt_table *tb, struct libmnt_iter *itr, struct libmnt_fs **fs) |
6bd8b7a7 | 318 | { |
59ae0ddd | 319 | int rc = 1; |
3fca8422 | 320 | |
6bd8b7a7 KZ |
321 | assert(tb); |
322 | assert(itr); | |
323 | assert(fs); | |
324 | ||
325 | if (!tb || !itr || !fs) | |
59ae0ddd | 326 | return -EINVAL; |
0532ba1d KZ |
327 | *fs = NULL; |
328 | ||
6bd8b7a7 KZ |
329 | if (!itr->head) |
330 | MNT_ITER_INIT(itr, &tb->ents); | |
331 | if (itr->p != itr->head) { | |
68164f6c | 332 | MNT_ITER_ITERATE(itr, *fs, struct libmnt_fs, ents); |
3fca8422 | 333 | rc = 0; |
6bd8b7a7 KZ |
334 | } |
335 | ||
3fca8422 KZ |
336 | return rc; |
337 | } | |
338 | ||
339 | /** | |
68164f6c | 340 | * mnt_table_find_next_fs: |
3fca8422 KZ |
341 | * @tb: table |
342 | * @itr: iterator | |
343 | * @match_func: function returns 1 or 0 | |
3d735589 | 344 | * @userdata: extra data for match_func |
3fca8422 KZ |
345 | * @fs: returns pointer to the next matching table entry |
346 | * | |
347 | * This function allows search in @tb. | |
348 | * | |
59ae0ddd | 349 | * Returns: negative number in case of error, 1 at end of table or 0 o success. |
3fca8422 | 350 | */ |
68164f6c KZ |
351 | int mnt_table_find_next_fs(struct libmnt_table *tb, struct libmnt_iter *itr, |
352 | int (*match_func)(struct libmnt_fs *, void *), void *userdata, | |
353 | struct libmnt_fs **fs) | |
3fca8422 KZ |
354 | { |
355 | if (!tb || !itr || !fs || !match_func) | |
59ae0ddd | 356 | return -EINVAL; |
3fca8422 | 357 | |
0ccfc837 | 358 | DBG(TAB, mnt_debug_h(tb, "lookup next fs")); |
20aae9d3 | 359 | |
3fca8422 KZ |
360 | if (!itr->head) |
361 | MNT_ITER_INIT(itr, &tb->ents); | |
362 | ||
363 | do { | |
364 | if (itr->p != itr->head) | |
68164f6c | 365 | MNT_ITER_ITERATE(itr, *fs, struct libmnt_fs, ents); |
3fca8422 KZ |
366 | else |
367 | break; /* end */ | |
368 | ||
3fca8422 KZ |
369 | if (match_func(*fs, userdata)) |
370 | return 0; | |
371 | } while(1); | |
372 | ||
26b4f9e4 | 373 | *fs = NULL; |
6bd8b7a7 KZ |
374 | return 1; |
375 | } | |
376 | ||
377 | /** | |
68164f6c | 378 | * mnt_table_set_iter: |
6bd8b7a7 KZ |
379 | * @tb: tab pointer |
380 | * @itr: iterator | |
381 | * @fs: tab entry | |
382 | * | |
383 | * Sets @iter to the position of @fs in the file @tb. | |
384 | * | |
59ae0ddd | 385 | * Returns: 0 on success, negative number in case of error. |
6bd8b7a7 | 386 | */ |
68164f6c | 387 | int mnt_table_set_iter(struct libmnt_table *tb, struct libmnt_iter *itr, struct libmnt_fs *fs) |
6bd8b7a7 KZ |
388 | { |
389 | assert(tb); | |
390 | assert(itr); | |
391 | assert(fs); | |
392 | ||
393 | if (!tb || !itr || !fs) | |
59ae0ddd | 394 | return -EINVAL; |
6bd8b7a7 KZ |
395 | |
396 | MNT_ITER_INIT(itr, &tb->ents); | |
397 | itr->p = &fs->ents; | |
398 | ||
399 | return 0; | |
400 | } | |
401 | ||
402 | /** | |
68164f6c | 403 | * mnt_table_find_target: |
6bd8b7a7 KZ |
404 | * @tb: tab pointer |
405 | * @path: mountpoint directory | |
406 | * @direction: MNT_ITER_{FORWARD,BACKWARD} | |
407 | * | |
408 | * Try to lookup an entry in given tab, possible are three iterations, first | |
409 | * with @path, second with realpath(@path) and third with realpath(@path) | |
410 | * against realpath(fs->target). The 2nd and 3rd iterations are not performed | |
68164f6c | 411 | * when @tb cache is not set (see mnt_table_set_cache()). |
6bd8b7a7 | 412 | * |
192c6aad | 413 | * Returns: a tab entry or NULL. |
6bd8b7a7 | 414 | */ |
68164f6c | 415 | struct libmnt_fs *mnt_table_find_target(struct libmnt_table *tb, const char *path, int direction) |
6bd8b7a7 | 416 | { |
68164f6c KZ |
417 | struct libmnt_iter itr; |
418 | struct libmnt_fs *fs = NULL; | |
6bd8b7a7 KZ |
419 | char *cn; |
420 | ||
421 | assert(tb); | |
422 | assert(path); | |
423 | ||
59ae0ddd KZ |
424 | if (!tb || !path) |
425 | return NULL; | |
426 | ||
3f31a959 | 427 | DBG(TAB, mnt_debug_h(tb, "lookup target: %s", path)); |
6bd8b7a7 KZ |
428 | |
429 | /* native @target */ | |
430 | mnt_reset_iter(&itr, direction); | |
68164f6c | 431 | while(mnt_table_next_fs(tb, &itr, &fs) == 0) |
6bd8b7a7 KZ |
432 | if (fs->target && strcmp(fs->target, path) == 0) |
433 | return fs; | |
434 | ||
435 | if (!tb->cache || !(cn = mnt_resolve_path(path, tb->cache))) | |
436 | return NULL; | |
437 | ||
68164f6c | 438 | /* canonicalized paths in struct libmnt_table */ |
6bd8b7a7 | 439 | mnt_reset_iter(&itr, direction); |
68164f6c | 440 | while(mnt_table_next_fs(tb, &itr, &fs) == 0) { |
6bd8b7a7 KZ |
441 | if (fs->target && strcmp(fs->target, cn) == 0) |
442 | return fs; | |
443 | } | |
444 | ||
68164f6c | 445 | /* non-canonicaled path in struct libmnt_table */ |
6bd8b7a7 | 446 | mnt_reset_iter(&itr, direction); |
68164f6c | 447 | while(mnt_table_next_fs(tb, &itr, &fs) == 0) { |
6bd8b7a7 | 448 | char *p; |
9dd75aa6 KZ |
449 | |
450 | if (!fs->target || !(fs->flags & MNT_FS_SWAP) || | |
451 | (*fs->target == '/' && *(fs->target + 1) == '\0')) | |
6bd8b7a7 | 452 | continue; |
9dd75aa6 | 453 | |
6bd8b7a7 KZ |
454 | p = mnt_resolve_path(fs->target, tb->cache); |
455 | if (strcmp(cn, p) == 0) | |
456 | return fs; | |
457 | } | |
458 | return NULL; | |
459 | } | |
460 | ||
461 | /** | |
68164f6c | 462 | * mnt_table_find_srcpath: |
6bd8b7a7 KZ |
463 | * @tb: tab pointer |
464 | * @path: source path (devname or dirname) | |
465 | * @direction: MNT_ITER_{FORWARD,BACKWARD} | |
466 | * | |
467 | * Try to lookup an entry in given tab, possible are four iterations, first | |
468 | * with @path, second with realpath(@path), third with tags (LABEL, UUID, ..) | |
469 | * from @path and fourth with realpath(@path) against realpath(entry->srcpath). | |
470 | * | |
471 | * The 2nd, 3rd and 4th iterations are not performed when @tb cache is not | |
68164f6c | 472 | * set (see mnt_table_set_cache()). |
6bd8b7a7 | 473 | * |
192c6aad | 474 | * Returns: a tab entry or NULL. |
6bd8b7a7 | 475 | */ |
68164f6c | 476 | struct libmnt_fs *mnt_table_find_srcpath(struct libmnt_table *tb, const char *path, int direction) |
6bd8b7a7 | 477 | { |
68164f6c KZ |
478 | struct libmnt_iter itr; |
479 | struct libmnt_fs *fs = NULL; | |
6bd8b7a7 KZ |
480 | int ntags = 0; |
481 | char *cn; | |
482 | const char *p; | |
483 | ||
484 | assert(tb); | |
485 | assert(path); | |
486 | ||
3f31a959 | 487 | DBG(TAB, mnt_debug_h(tb, "lookup srcpath: %s", path)); |
6bd8b7a7 KZ |
488 | |
489 | /* native paths */ | |
490 | mnt_reset_iter(&itr, direction); | |
68164f6c | 491 | while(mnt_table_next_fs(tb, &itr, &fs) == 0) { |
6bd8b7a7 KZ |
492 | p = mnt_fs_get_srcpath(fs); |
493 | if (p && strcmp(p, path) == 0) | |
494 | return fs; | |
495 | if (!p) | |
496 | /* mnt_fs_get_srcpath() returs nothing, it's TAG */ | |
497 | ntags++; | |
498 | } | |
499 | ||
500 | if (!tb->cache || !(cn = mnt_resolve_path(path, tb->cache))) | |
501 | return NULL; | |
502 | ||
68164f6c KZ |
503 | /* canonicalized paths in struct libmnt_table */ |
504 | if (ntags < mnt_table_get_nents(tb)) { | |
6bd8b7a7 | 505 | mnt_reset_iter(&itr, direction); |
68164f6c | 506 | while(mnt_table_next_fs(tb, &itr, &fs) == 0) { |
6bd8b7a7 KZ |
507 | p = mnt_fs_get_srcpath(fs); |
508 | if (p && strcmp(p, cn) == 0) | |
509 | return fs; | |
510 | } | |
511 | } | |
512 | ||
513 | /* evaluated tag */ | |
3fca8422 | 514 | if (ntags) { |
ba7232a1 KZ |
515 | int rc = mnt_cache_read_tags(tb->cache, cn); |
516 | ||
6bd8b7a7 | 517 | mnt_reset_iter(&itr, direction); |
6bd8b7a7 | 518 | |
ba7232a1 | 519 | if (rc == 0) { |
3fca8422 | 520 | /* @path's TAGs are in the cache */ |
68164f6c | 521 | while(mnt_table_next_fs(tb, &itr, &fs) == 0) { |
3fca8422 | 522 | const char *t, *v; |
6bd8b7a7 | 523 | |
3fca8422 KZ |
524 | if (mnt_fs_get_tag(fs, &t, &v)) |
525 | continue; | |
526 | ||
527 | if (mnt_cache_device_has_tag(tb->cache, cn, t, v)) | |
528 | return fs; | |
529 | } | |
ba7232a1 | 530 | } else if (rc < 0 && errno == EACCES) { |
3fca8422 KZ |
531 | /* @path is unaccessible, try evaluate all TAGs in @tb |
532 | * by udev symlinks -- this could be expensive on systems | |
533 | * with huge fstab/mtab */ | |
68164f6c | 534 | while(mnt_table_next_fs(tb, &itr, &fs) == 0) { |
3fca8422 KZ |
535 | const char *t, *v, *x; |
536 | if (mnt_fs_get_tag(fs, &t, &v)) | |
537 | continue; | |
538 | x = mnt_resolve_tag(t, v, tb->cache); | |
539 | if (x && !strcmp(x, cn)) | |
540 | return fs; | |
541 | } | |
6bd8b7a7 KZ |
542 | } |
543 | } | |
544 | ||
68164f6c KZ |
545 | /* non-canonicalized paths in struct libmnt_table */ |
546 | if (ntags <= mnt_table_get_nents(tb)) { | |
6bd8b7a7 | 547 | mnt_reset_iter(&itr, direction); |
68164f6c | 548 | while(mnt_table_next_fs(tb, &itr, &fs) == 0) { |
9dd75aa6 KZ |
549 | if (fs->flags & (MNT_FS_NET | MNT_FS_PSEUDO)) |
550 | continue; | |
6bd8b7a7 KZ |
551 | p = mnt_fs_get_srcpath(fs); |
552 | if (p) | |
553 | p = mnt_resolve_path(p, tb->cache); | |
554 | if (p && strcmp(cn, p) == 0) | |
555 | return fs; | |
556 | } | |
557 | } | |
558 | ||
559 | return NULL; | |
560 | } | |
561 | ||
562 | ||
563 | /** | |
68164f6c | 564 | * mnt_table_find_tag: |
6bd8b7a7 KZ |
565 | * @tb: tab pointer |
566 | * @tag: tag name (e.g "LABEL", "UUID", ...) | |
567 | * @val: tag value | |
568 | * @direction: MNT_ITER_{FORWARD,BACKWARD} | |
569 | * | |
570 | * Try to lookup an entry in given tab, first attempt is lookup by @tag and | |
571 | * @val, for the second attempt the tag is evaluated (converted to the device | |
68164f6c KZ |
572 | * name) and mnt_table_find_srcpath() is preformed. The second attempt is not |
573 | * performed when @tb cache is not set (see mnt_table_set_cache()). | |
6bd8b7a7 | 574 | |
192c6aad | 575 | * Returns: a tab entry or NULL. |
6bd8b7a7 | 576 | */ |
68164f6c | 577 | struct libmnt_fs *mnt_table_find_tag(struct libmnt_table *tb, const char *tag, |
6bd8b7a7 KZ |
578 | const char *val, int direction) |
579 | { | |
68164f6c KZ |
580 | struct libmnt_iter itr; |
581 | struct libmnt_fs *fs = NULL; | |
6bd8b7a7 KZ |
582 | |
583 | assert(tb); | |
584 | assert(tag); | |
585 | assert(val); | |
586 | ||
587 | if (!tb || !tag || !val) | |
588 | return NULL; | |
589 | ||
3f31a959 | 590 | DBG(TAB, mnt_debug_h(tb, "lookup by TAG: %s %s", tag, val)); |
6bd8b7a7 KZ |
591 | |
592 | /* look up by TAG */ | |
593 | mnt_reset_iter(&itr, direction); | |
68164f6c | 594 | while(mnt_table_next_fs(tb, &itr, &fs) == 0) { |
6bd8b7a7 KZ |
595 | if (fs->tagname && fs->tagval && |
596 | strcmp(fs->tagname, tag) == 0 && | |
597 | strcmp(fs->tagval, val) == 0) | |
598 | return fs; | |
599 | } | |
600 | ||
601 | if (tb->cache) { | |
602 | /* look up by device name */ | |
603 | char *cn = mnt_resolve_tag(tag, val, tb->cache); | |
604 | if (cn) | |
68164f6c | 605 | return mnt_table_find_srcpath(tb, cn, direction); |
6bd8b7a7 KZ |
606 | } |
607 | return NULL; | |
608 | } | |
609 | ||
610 | /** | |
68164f6c | 611 | * mnt_table_find_source: |
6bd8b7a7 KZ |
612 | * @tb: tab pointer |
613 | * @source: TAG or path | |
3d735589 | 614 | * @direction: MNT_ITER_{FORWARD,BACKWARD} |
6bd8b7a7 | 615 | * |
68164f6c | 616 | * This is high-level API for mnt_table_find_{srcpath,tag}. You needn't to care |
6bd8b7a7 | 617 | * about @source format (device, LABEL, UUID, ...). This function parses @source |
68164f6c | 618 | * and calls mnt_table_find_tag() or mnt_table_find_srcpath(). |
6bd8b7a7 | 619 | * |
192c6aad | 620 | * Returns: a tab entry or NULL. |
6bd8b7a7 | 621 | */ |
68164f6c | 622 | struct libmnt_fs *mnt_table_find_source(struct libmnt_table *tb, const char *source, int direction) |
6bd8b7a7 | 623 | { |
68164f6c | 624 | struct libmnt_fs *fs = NULL; |
6bd8b7a7 KZ |
625 | |
626 | assert(tb); | |
627 | assert(source); | |
628 | ||
629 | if (!tb || !source) | |
630 | return NULL; | |
631 | ||
3f31a959 | 632 | DBG(TAB, mnt_debug_h(tb, "lookup SOURCE: %s", source)); |
6bd8b7a7 KZ |
633 | |
634 | if (strchr(source, '=')) { | |
635 | char *tag, *val; | |
636 | ||
637 | if (blkid_parse_tag_string(source, &tag, &val) == 0) { | |
638 | ||
68164f6c | 639 | fs = mnt_table_find_tag(tb, tag, val, direction); |
6bd8b7a7 KZ |
640 | |
641 | free(tag); | |
642 | free(val); | |
643 | } | |
644 | } else | |
68164f6c | 645 | fs = mnt_table_find_srcpath(tb, source, direction); |
6bd8b7a7 KZ |
646 | |
647 | return fs; | |
648 | } | |
649 | ||
059c696f | 650 | /** |
68164f6c | 651 | * mnt_table_find_pair |
059c696f KZ |
652 | * @tb: tab pointer |
653 | * @source: TAG or path | |
654 | * @target: mountpoint | |
655 | * @direction: MNT_ITER_{FORWARD,BACKWARD} | |
656 | * | |
657 | * This function is implemented by mnt_fs_match_source() and | |
658 | * mnt_fs_match_target() functions. It means that this is more expensive that | |
68164f6c | 659 | * others mnt_table_find_* function, because every @tab entry is fully evaluated. |
059c696f KZ |
660 | * |
661 | * Returns: a tab entry or NULL. | |
662 | */ | |
68164f6c | 663 | struct libmnt_fs *mnt_table_find_pair(struct libmnt_table *tb, const char *source, |
059c696f KZ |
664 | const char *target, int direction) |
665 | { | |
68164f6c KZ |
666 | struct libmnt_fs *fs = NULL; |
667 | struct libmnt_iter itr; | |
059c696f KZ |
668 | |
669 | assert(tb); | |
670 | assert(source); | |
671 | assert(target); | |
672 | ||
673 | if (!tb || !source || !target) | |
674 | return NULL; | |
675 | ||
676 | DBG(TAB, mnt_debug_h(tb, "lookup SOURCE: %s TARGET: %s", source, target)); | |
677 | ||
678 | mnt_reset_iter(&itr, direction); | |
68164f6c | 679 | while(mnt_table_next_fs(tb, &itr, &fs) == 0) { |
059c696f KZ |
680 | |
681 | if (mnt_fs_match_target(fs, target, tb->cache) && | |
682 | mnt_fs_match_source(fs, source, tb->cache)) | |
683 | return fs; | |
684 | } | |
685 | ||
686 | return NULL; | |
687 | } | |
688 | ||
6bd8b7a7 | 689 | #ifdef TEST_PROGRAM |
fbb3eb85 | 690 | |
68164f6c | 691 | static int parser_errcb(struct libmnt_table *tb, const char *filename, int line) |
fbb3eb85 KZ |
692 | { |
693 | fprintf(stderr, "%s:%d: parse error\n", filename, line); | |
c3b0d5b3 KZ |
694 | |
695 | return 1; /* all errors are recoverable -- this is default */ | |
fbb3eb85 KZ |
696 | } |
697 | ||
68164f6c | 698 | struct libmnt_table *create_table(const char *file) |
6bd8b7a7 | 699 | { |
68164f6c | 700 | struct libmnt_table *tb; |
6bd8b7a7 KZ |
701 | |
702 | if (!file) | |
703 | return NULL; | |
68164f6c | 704 | tb = mnt_new_table(); |
6bd8b7a7 KZ |
705 | if (!tb) |
706 | goto err; | |
fbb3eb85 | 707 | |
68164f6c | 708 | mnt_table_set_parser_errcb(tb, parser_errcb); |
fbb3eb85 | 709 | |
68164f6c | 710 | if (mnt_table_parse_file(tb, file) != 0) |
6bd8b7a7 | 711 | goto err; |
6bd8b7a7 KZ |
712 | return tb; |
713 | err: | |
c3b0d5b3 | 714 | fprintf(stderr, "%s: parsing failed\n", file); |
68164f6c | 715 | mnt_free_table(tb); |
6bd8b7a7 KZ |
716 | return NULL; |
717 | } | |
718 | ||
68164f6c | 719 | int test_copy_fs(struct libmnt_test *ts, int argc, char *argv[]) |
6d94f2dc | 720 | { |
68164f6c KZ |
721 | struct libmnt_table *tb; |
722 | struct libmnt_fs *fs; | |
059c696f | 723 | int rc = -1; |
6d94f2dc | 724 | |
68164f6c | 725 | tb = create_table(argv[1]); |
6d94f2dc KZ |
726 | if (!tb) |
727 | return -1; | |
728 | ||
68164f6c | 729 | fs = mnt_table_find_target(tb, "/", MNT_ITER_FORWARD); |
6d94f2dc | 730 | if (!fs) |
059c696f | 731 | goto done; |
6d94f2dc KZ |
732 | |
733 | printf("ORIGINAL:\n"); | |
734 | mnt_fs_print_debug(fs, stdout); | |
735 | ||
736 | fs = mnt_copy_fs(fs); | |
737 | if (!fs) | |
059c696f | 738 | goto done; |
6d94f2dc KZ |
739 | |
740 | printf("COPY:\n"); | |
741 | mnt_fs_print_debug(fs, stdout); | |
742 | mnt_free_fs(fs); | |
059c696f KZ |
743 | rc = 0; |
744 | done: | |
68164f6c | 745 | mnt_free_table(tb); |
059c696f | 746 | return rc; |
6d94f2dc KZ |
747 | } |
748 | ||
68164f6c | 749 | int test_parse(struct libmnt_test *ts, int argc, char *argv[]) |
6bd8b7a7 | 750 | { |
68164f6c KZ |
751 | struct libmnt_table *tb = NULL; |
752 | struct libmnt_iter *itr = NULL; | |
753 | struct libmnt_fs *fs; | |
059c696f | 754 | int rc = -1; |
6bd8b7a7 | 755 | |
68164f6c | 756 | tb = create_table(argv[1]); |
6bd8b7a7 KZ |
757 | if (!tb) |
758 | return -1; | |
759 | ||
efe73c3e KZ |
760 | itr = mnt_new_iter(MNT_ITER_FORWARD); |
761 | if (!itr) | |
059c696f | 762 | goto done; |
fbb3eb85 | 763 | |
68164f6c | 764 | while(mnt_table_next_fs(tb, itr, &fs) == 0) |
efe73c3e | 765 | mnt_fs_print_debug(fs, stdout); |
059c696f KZ |
766 | rc = 0; |
767 | done: | |
efe73c3e | 768 | mnt_free_iter(itr); |
68164f6c | 769 | mnt_free_table(tb); |
059c696f | 770 | return rc; |
6bd8b7a7 KZ |
771 | } |
772 | ||
68164f6c | 773 | int test_find(struct libmnt_test *ts, int argc, char *argv[], int dr) |
6bd8b7a7 | 774 | { |
68164f6c KZ |
775 | struct libmnt_table *tb; |
776 | struct libmnt_fs *fs = NULL; | |
777 | struct libmnt_cache *mpc = NULL; | |
6bd8b7a7 | 778 | const char *file, *find, *what; |
059c696f | 779 | int rc = -1; |
6bd8b7a7 KZ |
780 | |
781 | if (argc != 4) { | |
782 | fprintf(stderr, "try --help\n"); | |
059c696f | 783 | return -EINVAL; |
6bd8b7a7 KZ |
784 | } |
785 | ||
786 | file = argv[1], find = argv[2], what = argv[3]; | |
787 | ||
68164f6c | 788 | tb = create_table(file); |
6bd8b7a7 | 789 | if (!tb) |
059c696f | 790 | goto done; |
6bd8b7a7 KZ |
791 | |
792 | /* create a cache for canonicalized paths */ | |
793 | mpc = mnt_new_cache(); | |
794 | if (!mpc) | |
059c696f | 795 | goto done; |
68164f6c | 796 | mnt_table_set_cache(tb, mpc); |
6bd8b7a7 KZ |
797 | |
798 | if (strcasecmp(find, "source") == 0) | |
68164f6c | 799 | fs = mnt_table_find_source(tb, what, dr); |
6bd8b7a7 | 800 | else if (strcasecmp(find, "target") == 0) |
68164f6c | 801 | fs = mnt_table_find_target(tb, what, dr); |
6bd8b7a7 KZ |
802 | |
803 | if (!fs) | |
804 | fprintf(stderr, "%s: not found %s '%s'\n", file, find, what); | |
805 | else { | |
5e31c2c8 | 806 | mnt_fs_print_debug(fs, stdout); |
059c696f | 807 | rc = 0; |
6bd8b7a7 | 808 | } |
059c696f | 809 | done: |
68164f6c | 810 | mnt_free_table(tb); |
6bd8b7a7 | 811 | mnt_free_cache(mpc); |
059c696f | 812 | return rc; |
6bd8b7a7 KZ |
813 | } |
814 | ||
68164f6c | 815 | int test_find_bw(struct libmnt_test *ts, int argc, char *argv[]) |
6bd8b7a7 KZ |
816 | { |
817 | return test_find(ts, argc, argv, MNT_ITER_BACKWARD); | |
818 | } | |
819 | ||
68164f6c | 820 | int test_find_fw(struct libmnt_test *ts, int argc, char *argv[]) |
6bd8b7a7 KZ |
821 | { |
822 | return test_find(ts, argc, argv, MNT_ITER_FORWARD); | |
823 | } | |
824 | ||
68164f6c | 825 | int test_find_pair(struct libmnt_test *ts, int argc, char *argv[]) |
059c696f | 826 | { |
68164f6c KZ |
827 | struct libmnt_table *tb; |
828 | struct libmnt_fs *fs; | |
059c696f KZ |
829 | int rc = -1; |
830 | ||
68164f6c | 831 | tb = create_table(argv[1]); |
059c696f KZ |
832 | if (!tb) |
833 | return -1; | |
834 | ||
68164f6c | 835 | fs = mnt_table_find_pair(tb, argv[2], argv[3], MNT_ITER_FORWARD); |
059c696f KZ |
836 | if (!fs) |
837 | goto done; | |
838 | ||
839 | mnt_fs_print_debug(fs, stdout); | |
840 | rc = 0; | |
841 | done: | |
68164f6c | 842 | mnt_free_table(tb); |
059c696f KZ |
843 | return rc; |
844 | } | |
845 | ||
6bd8b7a7 KZ |
846 | int main(int argc, char *argv[]) |
847 | { | |
68164f6c | 848 | struct libmnt_test tss[] = { |
6bd8b7a7 KZ |
849 | { "--parse", test_parse, "<file> parse and print tab" }, |
850 | { "--find-forward", test_find_fw, "<file> <source|target> <string>" }, | |
851 | { "--find-backward", test_find_bw, "<file> <source|target> <string>" }, | |
059c696f | 852 | { "--find-pair", test_find_pair, "<file> <source> <target>" }, |
6d94f2dc | 853 | { "--copy-fs", test_copy_fs, "<file> copy root FS from the file" }, |
6bd8b7a7 KZ |
854 | { NULL } |
855 | }; | |
856 | ||
857 | return mnt_run_test(tss, argc, argv); | |
858 | } | |
859 | ||
860 | #endif /* TEST_PROGRAM */ |