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