]> git.ipfire.org Git - thirdparty/util-linux.git/blame - shlibs/mount/src/tab.c
libmount: remove mnt_tab_strerr()
[thirdparty/util-linux.git] / shlibs / mount / src / tab.c
CommitLineData
6bd8b7a7 1/*
192c6aad 2 * Copyright (C) 2008-2010 Karel Zak <kzak@redhat.com>
6bd8b7a7
KZ
3 *
4 * This file may be redistributed under the terms of the
5 * GNU Lesser General Public License.
192c6aad
KZ
6 */
7
8/**
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 */
72mnt_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;
87err:
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 */
98void 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 */
118int 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 */
140int 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 */
155mnt_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 */
167const 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 */
182int 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 */
208int 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 */
229int 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 */
271int 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 */
346int 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 */
379int 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 */
416int 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 */
444mnt_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 */
500mnt_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 */
600mnt_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 */
646mnt_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 */
684int 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 */
713int 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;
758error:
759 if (f)
760 fclose(f);
761 return -1;
762}
763
764#ifdef TEST_PROGRAM
6bd8b7a7
KZ
765mnt_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;
777err:
778 mnt_free_tab(tb);
779 return NULL;
780}
781
782int 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);
797err:
798 mnt_free_iter(itr);
6bd8b7a7
KZ
799 mnt_free_tab(tb);
800 return 0;
801}
802
803int 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;
849err:
850 return -1;
851}
852
853int test_find_bw(struct mtest *ts, int argc, char *argv[])
854{
855 return test_find(ts, argc, argv, MNT_ITER_BACKWARD);
856}
857
858int test_find_fw(struct mtest *ts, int argc, char *argv[])
859{
860 return test_find(ts, argc, argv, MNT_ITER_FORWARD);
861}
862
863int 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 */