]> git.ipfire.org Git - thirdparty/util-linux.git/blame_incremental - libmount/src/fs.c
libmount: always trust the source of a pseudofs
[thirdparty/util-linux.git] / libmount / src / fs.c
... / ...
CommitLineData
1/*
2 * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com>
3 *
4 * This file may be redistributed under the terms of the
5 * GNU Lesser General Public License.
6 */
7
8/**
9 * SECTION: fs
10 * @title: Filesystem
11 * @short_description: represents one entry from fstab, mtab, or mountinfo file
12 *
13 */
14#include <ctype.h>
15#include <blkid.h>
16#include <stddef.h>
17
18#include "mountP.h"
19#include "strutils.h"
20
21/**
22 * mnt_new_fs:
23 *
24 * Returns: newly allocated struct libmnt_fs.
25 */
26struct libmnt_fs *mnt_new_fs(void)
27{
28 struct libmnt_fs *fs = calloc(1, sizeof(*fs));
29 if (!fs)
30 return NULL;
31
32 /*DBG(FS, mnt_debug_h(fs, "alloc"));*/
33 INIT_LIST_HEAD(&fs->ents);
34 return fs;
35}
36
37/**
38 * mnt_free_fs:
39 * @fs: fs pointer
40 *
41 * Deallocates the fs.
42 */
43void mnt_free_fs(struct libmnt_fs *fs)
44{
45 if (!fs)
46 return;
47 list_del(&fs->ents);
48
49 /*DBG(FS, mnt_debug_h(fs, "free"));*/
50
51 free(fs->source);
52 free(fs->bindsrc);
53 free(fs->tagname);
54 free(fs->tagval);
55 free(fs->root);
56 free(fs->target);
57 free(fs->fstype);
58 free(fs->optstr);
59 free(fs->vfs_optstr);
60 free(fs->fs_optstr);
61 free(fs->user_optstr);
62 free(fs->attrs);
63
64 free(fs);
65}
66
67/**
68 * mnt_reset_fs:
69 * @fs: fs pointer
70 *
71 * Resets (zeroize) @fs.
72 */
73void mnt_reset_fs(struct libmnt_fs *fs)
74{
75 if (fs)
76 memset(fs, 0, sizeof(*fs));
77}
78
79static inline int update_str(char **dest, const char *src)
80{
81 size_t sz;
82 char *x;
83
84 assert(dest);
85
86 if (!src) {
87 free(*dest);
88 *dest = NULL;
89 return 0; /* source (old) is empty */
90 }
91
92 sz = strlen(src) + 1;
93 x = realloc(*dest, sz);
94 if (!x)
95 return -ENOMEM;
96 *dest = x;
97 memcpy(*dest, src, sz);
98 return 0;
99}
100
101static inline int cpy_str_at_offset(void *new, const void *old, size_t offset)
102{
103 char **o = (char **) (old + offset);
104 char **n = (char **) (new + offset);
105
106 if (*n)
107 return 0; /* already set, not overwrite */
108
109 return update_str(n, *o);
110}
111
112/**
113 * mnt_copy_fs:
114 * @dest: destination FS
115 * @src: source FS
116 *
117 * If @dest is NULL, then a new FS is allocated, if any @dest field is already
118 * set then the field is NOT overwrited.
119 *
120 * This function does not copy userdata (se mnt_fs_set_userdata()). A new copy is
121 * not linked with any existing mnt_tab.
122 *
123 * Returns: @dest or NULL in case of error
124 */
125struct libmnt_fs *mnt_copy_fs(struct libmnt_fs *dest,
126 const struct libmnt_fs *src)
127{
128 const struct libmnt_fs *org = dest;
129
130 if (!dest) {
131 dest = mnt_new_fs();
132 if (!dest)
133 return NULL;
134 }
135
136 /*DBG(FS, mnt_debug_h(dest, "copy from %p", src));*/
137
138 dest->id = src->id;
139 dest->parent = src->parent;
140 dest->devno = src->devno;
141
142 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, source)))
143 goto err;
144 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, tagname)))
145 goto err;
146 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, tagval)))
147 goto err;
148 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, root)))
149 goto err;
150 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, target)))
151 goto err;
152 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, fstype)))
153 goto err;
154 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, optstr)))
155 goto err;
156 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, vfs_optstr)))
157 goto err;
158 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, fs_optstr)))
159 goto err;
160 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, user_optstr)))
161 goto err;
162 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, attrs)))
163 goto err;
164 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, bindsrc)))
165 goto err;
166
167 dest->freq = src->freq;
168 dest->passno = src->passno;
169 dest->flags = src->flags;
170
171 return dest;
172err:
173 if (!org)
174 mnt_free_fs(dest);
175 return NULL;
176}
177
178/*
179 * This function copies all @fs description except information that does not
180 * belong to /etc/mtab (e.g. VFS and userspace mount options with MNT_NOMTAB
181 * mask).
182 *
183 * Returns: copy of @fs.
184 */
185struct libmnt_fs *mnt_copy_mtab_fs(const struct libmnt_fs *fs)
186{
187 struct libmnt_fs *n = mnt_new_fs();
188
189 if (!n)
190 return NULL;
191
192 if (cpy_str_at_offset(n, fs, offsetof(struct libmnt_fs, source)))
193 goto err;
194 if (cpy_str_at_offset(n, fs, offsetof(struct libmnt_fs, target)))
195 goto err;
196 if (cpy_str_at_offset(n, fs, offsetof(struct libmnt_fs, fstype)))
197 goto err;
198
199 if (fs->vfs_optstr) {
200 char *p = NULL;
201 mnt_optstr_get_options(fs->vfs_optstr, &p,
202 mnt_get_builtin_optmap(MNT_LINUX_MAP),
203 MNT_NOMTAB);
204 n->vfs_optstr = p;
205 }
206
207 if (fs->user_optstr) {
208 char *p = NULL;
209 mnt_optstr_get_options(fs->user_optstr, &p,
210 mnt_get_builtin_optmap(MNT_USERSPACE_MAP),
211 MNT_NOMTAB);
212 n->user_optstr = p;
213 }
214
215 if (cpy_str_at_offset(n, fs, offsetof(struct libmnt_fs, fs_optstr)))
216 goto err;
217
218 /* we cannot copy original optstr, the new optstr has to be without
219 * non-mtab options -- so, let's generate a new string */
220 n->optstr = mnt_fs_strdup_options(n);
221
222 n->freq = fs->freq;
223 n->passno = fs->passno;
224 n->flags = fs->flags;
225
226 return n;
227err:
228 mnt_free_fs(n);
229 return NULL;
230
231}
232
233/**
234 * mnt_fs_get_userdata:
235 * @fs: struct libmnt_file instance
236 *
237 * Returns: private data set by mnt_fs_set_userdata() or NULL.
238 */
239void *mnt_fs_get_userdata(struct libmnt_fs *fs)
240{
241 return fs ? fs->userdata : NULL;
242}
243
244/**
245 * mnt_fs_set_userdata:
246 * @fs: struct libmnt_file instance
247 * @data: user data
248 *
249 * The "userdata" are library independent data.
250 *
251 * Returns: 0 or negative number in case of error (if @fs is NULL).
252 */
253int mnt_fs_set_userdata(struct libmnt_fs *fs, void *data)
254{
255 if (!fs)
256 return -EINVAL;
257 fs->userdata = data;
258 return 0;
259}
260
261/**
262 * mnt_fs_get_srcpath:
263 * @fs: struct libmnt_file (fstab/mtab/mountinfo) fs
264 *
265 * The mount "source path" is:
266 * - a directory for 'bind' mounts (in fstab or mtab only)
267 * - a device name for standard mounts
268 *
269 * See also mnt_fs_get_tag() and mnt_fs_get_source().
270 *
271 * Returns: mount source path or NULL in case of error or when the path
272 * is not defined.
273 */
274const char *mnt_fs_get_srcpath(struct libmnt_fs *fs)
275{
276 assert(fs);
277 if (!fs)
278 return NULL;
279
280 /* fstab-like fs */
281 if (fs->tagname)
282 return NULL; /* the source contains a "NAME=value" */
283 return fs->source;
284}
285
286/**
287 * mnt_fs_get_source:
288 * @fs: struct libmnt_file (fstab/mtab/mountinfo) fs
289 *
290 * Returns: mount source. Note that the source could be unparsed TAG
291 * (LABEL/UUID). See also mnt_fs_get_srcpath() and mnt_fs_get_tag().
292 */
293const char *mnt_fs_get_source(struct libmnt_fs *fs)
294{
295 return fs ? fs->source : NULL;
296}
297
298/*
299 * Used by parser ONLY (@source has to be allocated on error)
300 */
301int __mnt_fs_set_source_ptr(struct libmnt_fs *fs, char *source)
302{
303 char *t = NULL, *v = NULL;
304
305 assert(fs);
306
307 if (source && !strcmp(source, "none")) {
308 free(source);
309 source = NULL;
310
311 } else if (source && strchr(source, '=')) {
312 if (blkid_parse_tag_string(source, &t, &v) != 0)
313 return -1;
314 }
315
316 if (fs->source != source)
317 free(fs->source);
318
319 free(fs->tagname);
320 free(fs->tagval);
321
322 fs->source = source;
323 fs->tagname = t;
324 fs->tagval = v;
325 return 0;
326}
327
328/**
329 * mnt_fs_set_source:
330 * @fs: fstab/mtab/mountinfo entry
331 * @source: new source
332 *
333 * This function creates a private copy (strdup()) of @source.
334 *
335 * Returns: 0 on success or negative number in case of error.
336 */
337int mnt_fs_set_source(struct libmnt_fs *fs, const char *source)
338{
339 char *p = NULL;
340 int rc;
341
342 if (!fs)
343 return -EINVAL;
344 if (source) {
345 p = strdup(source);
346 if (!p)
347 return -ENOMEM;
348 }
349
350 rc = __mnt_fs_set_source_ptr(fs, p);
351 if (rc)
352 free(p);
353 return rc;
354}
355
356/**
357 * mnt_fs_get_tag:
358 * @fs: fs
359 * @name: returns pointer to NAME string
360 * @value: returns pointer to VALUE string
361 *
362 * "TAG" is NAME=VALUE (e.g. LABEL=foo)
363 *
364 * The TAG is the first column in the fstab file. The TAG or "srcpath" has to
365 * be always set for all entries.
366 *
367 * See also mnt_fs_get_source().
368 *
369 * <informalexample>
370 * <programlisting>
371 * char *src;
372 * struct libmnt_fs *fs = mnt_table_find_target(tb, "/home", MNT_ITER_FORWARD);
373 *
374 * if (!fs)
375 * goto err;
376 *
377 * src = mnt_fs_get_srcpath(fs);
378 * if (!src) {
379 * char *tag, *val;
380 * if (mnt_fs_get_tag(fs, &tag, &val) == 0)
381 * printf("%s: %s\n", tag, val); // LABEL or UUID
382 * } else
383 * printf("device: %s\n", src); // device or bind path
384 * </programlisting>
385 * </informalexample>
386 *
387 * Returns: 0 on success or negative number in case that a TAG is not defined.
388 */
389int mnt_fs_get_tag(struct libmnt_fs *fs, const char **name, const char **value)
390{
391 if (fs == NULL || !fs->tagname)
392 return -EINVAL;
393 if (name)
394 *name = fs->tagname;
395 if (value)
396 *value = fs->tagval;
397 return 0;
398}
399
400/**
401 * mnt_fs_get_target:
402 * @fs: fstab/mtab/mountinfo entry pointer
403 *
404 * Returns: pointer to mountpoint path or NULL
405 */
406const char *mnt_fs_get_target(struct libmnt_fs *fs)
407{
408 assert(fs);
409 return fs ? fs->target : NULL;
410}
411
412/**
413 * mnt_fs_set_target:
414 * @fs: fstab/mtab/mountinfo entry
415 * @target: mountpoint
416 *
417 * This function creates a private copy (strdup()) of @target.
418 *
419 * Returns: 0 on success or negative number in case of error.
420 */
421int mnt_fs_set_target(struct libmnt_fs *fs, const char *target)
422{
423 char *p = NULL;
424
425 assert(fs);
426
427 if (!fs)
428 return -EINVAL;
429 if (target) {
430 p = strdup(target);
431 if (!p)
432 return -ENOMEM;
433 }
434 free(fs->target);
435 fs->target = p;
436
437 return 0;
438}
439
440int __mnt_fs_get_flags(struct libmnt_fs *fs)
441{
442 return fs ? fs->flags : 0;
443}
444
445int __mnt_fs_set_flags(struct libmnt_fs *fs, int flags)
446{
447 if (fs) {
448 fs->flags = flags;
449 return 0;
450 }
451 return -EINVAL;
452}
453
454/**
455 * mnt_fs_is_kernel:
456 * @fs: filesystem
457 *
458 * Returns: 1 if the filesystem description is read from kernel e.g. /proc/mounts.
459 */
460int mnt_fs_is_kernel(struct libmnt_fs *fs)
461{
462 return __mnt_fs_get_flags(fs) & MNT_FS_KERNEL;
463}
464
465/**
466 * mnt_fs_get_fstype:
467 * @fs: fstab/mtab/mountinfo entry pointer
468 *
469 * Returns: pointer to filesystem type.
470 */
471const char *mnt_fs_get_fstype(struct libmnt_fs *fs)
472{
473 assert(fs);
474 return fs ? fs->fstype : NULL;
475}
476
477/* Used by struct libmnt_file parser only */
478int __mnt_fs_set_fstype_ptr(struct libmnt_fs *fs, char *fstype)
479{
480 assert(fs);
481
482 if (fstype != fs->fstype)
483 free(fs->fstype);
484
485 fs->fstype = fstype;
486 fs->flags &= ~MNT_FS_PSEUDO;
487 fs->flags &= ~MNT_FS_NET;
488 fs->flags &= ~MNT_FS_SWAP;
489
490 /* save info about pseudo filesystems */
491 if (fs->fstype) {
492 if (mnt_fstype_is_pseudofs(fs->fstype))
493 fs->flags |= MNT_FS_PSEUDO;
494 else if (mnt_fstype_is_netfs(fs->fstype))
495 fs->flags |= MNT_FS_NET;
496 else if (!strcmp(fs->fstype, "swap"))
497 fs->flags |= MNT_FS_SWAP;
498 }
499 return 0;
500}
501
502/**
503 * mnt_fs_set_fstype:
504 * @fs: fstab/mtab/mountinfo entry
505 * @fstype: filesystem type
506 *
507 * This function creates a private copy (strdup()) of @fstype.
508 *
509 * Returns: 0 on success or negative number in case of error.
510 */
511int mnt_fs_set_fstype(struct libmnt_fs *fs, const char *fstype)
512{
513 char *p = NULL;
514
515 if (!fs)
516 return -EINVAL;
517 if (fstype) {
518 p = strdup(fstype);
519 if (!p)
520 return -ENOMEM;
521 }
522 return __mnt_fs_set_fstype_ptr(fs, p);
523}
524
525/*
526 * Merges @vfs and @fs options strings into a new string.
527 * This function cares about 'ro/rw' options. The 'ro' is
528 * always used if @vfs or @fs is read-only.
529 * For example:
530 *
531 * mnt_merge_optstr("rw,noexec", "ro,journal=update")
532 *
533 * returns: "ro,noexec,journal=update"
534 *
535 * mnt_merge_optstr("rw,noexec", "rw,journal=update")
536 *
537 * returns: "rw,noexec,journal=update"
538 */
539static char *merge_optstr(const char *vfs, const char *fs)
540{
541 char *res, *p;
542 size_t sz;
543 int ro = 0, rw = 0;
544
545 if (!vfs && !fs)
546 return NULL;
547 if (!vfs || !fs)
548 return strdup(fs ? fs : vfs);
549 if (!strcmp(vfs, fs))
550 return strdup(vfs); /* e.g. "aaa" and "aaa" */
551
552 /* leave space for leading "r[ow],", "," and trailing zero */
553 sz = strlen(vfs) + strlen(fs) + 5;
554 res = malloc(sz);
555 if (!res)
556 return NULL;
557 p = res + 3; /* make a room for rw/ro flag */
558
559 snprintf(p, sz - 3, "%s,%s", vfs, fs);
560
561 /* remove 'rw' flags */
562 rw += !mnt_optstr_remove_option(&p, "rw"); /* from vfs */
563 rw += !mnt_optstr_remove_option(&p, "rw"); /* from fs */
564
565 /* remove 'ro' flags if necessary */
566 if (rw != 2) {
567 ro += !mnt_optstr_remove_option(&p, "ro");
568 if (ro + rw < 2)
569 ro += !mnt_optstr_remove_option(&p, "ro");
570 }
571
572 if (!strlen(p))
573 memcpy(res, ro ? "ro" : "rw", 3);
574 else
575 memcpy(res, ro ? "ro," : "rw,", 3);
576 return res;
577}
578
579/**
580 * mnt_fs_strdup_options:
581 * @fs: fstab/mtab/mountinfo entry pointer
582 *
583 * Merges all mount options (VFS, FS and userspace) to the one options string
584 * and returns the result. This function does not modigy @fs.
585 *
586 * Returns: pointer to string (can be freed by free(3)) or NULL in case of error.
587 */
588char *mnt_fs_strdup_options(struct libmnt_fs *fs)
589{
590 char *res;
591
592 assert(fs);
593
594 errno = 0;
595
596 if (fs->optstr)
597 return strdup(fs->optstr);
598
599 res = merge_optstr(fs->vfs_optstr, fs->fs_optstr);
600 if (!res && errno)
601 return NULL;
602 if (fs->user_optstr) {
603 if (mnt_optstr_append_option(&res, fs->user_optstr, NULL)) {
604 free(res);
605 res = NULL;
606 }
607 }
608 return res;
609}
610
611/**
612 * mnt_fs_get_options:
613 * @fs: fstab/mtab/mountinfo entry pointer
614 *
615 * Returns: pointer to string or NULL in case of error.
616 */
617const char *mnt_fs_get_options(struct libmnt_fs *fs)
618{
619 assert(fs);
620 return fs ? fs->optstr : NULL;
621}
622
623
624/**
625 * mnt_fs_set_options:
626 * @fs: fstab/mtab/mountinfo entry pointer
627 * @optstr: options string
628 *
629 * Splits @optstr to VFS, FS and userspace mount options and update relevat
630 * parts of @fs.
631 *
632 * Returns: 0 on success, or negative number icase of error.
633 */
634int mnt_fs_set_options(struct libmnt_fs *fs, const char *optstr)
635{
636 char *v = NULL, *f = NULL, *u = NULL, *n = NULL;
637
638 assert(fs);
639
640 if (!fs)
641 return -EINVAL;
642 if (optstr) {
643 int rc = mnt_split_optstr(optstr, &u, &v, &f, 0, 0);
644 if (rc)
645 return rc;
646 n = strdup(optstr);
647 if (!n)
648 return -ENOMEM;
649 }
650
651 free(fs->fs_optstr);
652 free(fs->vfs_optstr);
653 free(fs->user_optstr);
654 free(fs->optstr);
655
656 fs->fs_optstr = f;
657 fs->vfs_optstr = v;
658 fs->user_optstr = u;
659 fs->optstr = n;
660
661 return 0;
662}
663
664/**
665 * mnt_fs_append_options:
666 * @fs: fstab/mtab/mountinfo entry
667 * @optstr: mount options
668 *
669 * Parses (splits) @optstr and appends results to VFS, FS and userspace lists
670 * of options.
671 *
672 * If @optstr is NULL then @fs is not modified and 0 is returned.
673 *
674 * Returns: 0 on success or negative number in case of error.
675 */
676int mnt_fs_append_options(struct libmnt_fs *fs, const char *optstr)
677{
678 char *v = NULL, *f = NULL, *u = NULL;
679 int rc;
680
681 assert(fs);
682
683 if (!fs)
684 return -EINVAL;
685 if (!optstr)
686 return 0;
687
688 rc = mnt_split_optstr((char *) optstr, &u, &v, &f, 0, 0);
689 if (!rc && v)
690 rc = mnt_optstr_append_option(&fs->vfs_optstr, v, NULL);
691 if (!rc && f)
692 rc = mnt_optstr_append_option(&fs->fs_optstr, f, NULL);
693 if (!rc && u)
694 rc = mnt_optstr_append_option(&fs->user_optstr, u, NULL);
695 if (!rc)
696 rc = mnt_optstr_append_option(&fs->optstr, optstr, NULL);
697
698 free(v);
699 free(f);
700 free(u);
701
702 return rc;
703}
704
705/**
706 * mnt_fs_prepend_options:
707 * @fs: fstab/mtab/mountinfo entry
708 * @optstr: mount options
709 *
710 * Parses (splits) @optstr and prepands results to VFS, FS and userspace lists
711 * of options.
712 *
713 * If @optstr is NULL then @fs is not modified and 0 is returned.
714 *
715 * Returns: 0 on success or negative number in case of error.
716 */
717int mnt_fs_prepend_options(struct libmnt_fs *fs, const char *optstr)
718{
719 char *v = NULL, *f = NULL, *u = NULL;
720 int rc;
721
722 assert(fs);
723
724 if (!fs)
725 return -EINVAL;
726 if (!optstr)
727 return 0;
728
729 rc = mnt_split_optstr((char *) optstr, &u, &v, &f, 0, 0);
730 if (!rc && v)
731 rc = mnt_optstr_prepend_option(&fs->vfs_optstr, v, NULL);
732 if (!rc && f)
733 rc = mnt_optstr_prepend_option(&fs->fs_optstr, f, NULL);
734 if (!rc && u)
735 rc = mnt_optstr_prepend_option(&fs->user_optstr, u, NULL);
736 if (!rc)
737 rc = mnt_optstr_prepend_option(&fs->optstr, optstr, NULL);
738
739 free(v);
740 free(f);
741 free(u);
742
743 return rc;
744}
745
746/*
747 * mnt_fs_get_fs_options:
748 * @fs: fstab/mtab/mountinfo entry pointer
749 *
750 * Returns: pointer to superblock (fs-depend) mount option string or NULL.
751 */
752const char *mnt_fs_get_fs_options(struct libmnt_fs *fs)
753{
754 assert(fs);
755 return fs ? fs->fs_optstr : NULL;
756}
757
758/**
759 * mnt_fs_get_vfs_options:
760 * @fs: fstab/mtab entry pointer
761 *
762 * Returns: pointer to fs-independent (VFS) mount option string or NULL.
763 */
764const char *mnt_fs_get_vfs_options(struct libmnt_fs *fs)
765{
766 assert(fs);
767 return fs ? fs->vfs_optstr : NULL;
768}
769
770/**
771 * mnt_fs_get_user_options:
772 * @fs: fstab/mtab entry pointer
773 *
774 * Returns: pointer to userspace mount option string or NULL.
775 */
776const char *mnt_fs_get_user_options(struct libmnt_fs *fs)
777{
778 assert(fs);
779 return fs ? fs->user_optstr : NULL;
780}
781
782/**
783 * mnt_fs_get_attributes:
784 * @fs: fstab/mtab entry pointer
785 *
786 * Returns: pointer to attributes string or NULL.
787 */
788const char *mnt_fs_get_attributes(struct libmnt_fs *fs)
789{
790 assert(fs);
791 return fs ? fs->attrs : NULL;
792}
793
794/**
795 * mnt_fs_set_attributes:
796 * @fs: fstab/mtab/mountinfo entry
797 * @optstr: options string
798 *
799 * Sets mount attributes. The attributes are mount(2) and mount(8) independent
800 * options, these options are not send to kernel and are not interpreted by
801 * libmount. The attributes are stored in /run/mount/utab only.
802 *
803 * The atrtributes are managed by libmount in userspace only. It's possible
804 * that information stored in userspace will not be available for libmount
805 * after CLONE_FS unshare. Be carefull, and don't use attributes if possible.
806 *
807 * Returns: 0 on success or negative number in case of error.
808 */
809int mnt_fs_set_attributes(struct libmnt_fs *fs, const char *optstr)
810{
811 char *p = NULL;
812
813 if (!fs)
814 return -EINVAL;
815 if (optstr) {
816 p = strdup(optstr);
817 if (!p)
818 return -ENOMEM;
819 }
820 free(fs->attrs);
821 fs->attrs = p;
822
823 return 0;
824}
825
826/**
827 * mnt_fs_append_attributes
828 * @fs: fstab/mtab/mountinfo entry
829 * @optstr: options string
830 *
831 * Appends mount attributes. (See mnt_fs_set_attributes()).
832 *
833 * Returns: 0 on success or negative number in case of error.
834 */
835int mnt_fs_append_attributes(struct libmnt_fs *fs, const char *optstr)
836{
837 if (!fs)
838 return -EINVAL;
839 if (!optstr)
840 return 0;
841 return mnt_optstr_append_option(&fs->attrs, optstr, NULL);
842}
843
844/**
845 * mnt_fs_prepend_attributes
846 * @fs: fstab/mtab/mountinfo entry
847 * @optstr: options string
848 *
849 * Prepends mount attributes. (See mnt_fs_set_attributes()).
850 *
851 * Returns: 0 on success or negative number in case of error.
852 */
853int mnt_fs_prepend_attributes(struct libmnt_fs *fs, const char *optstr)
854{
855 if (!fs)
856 return -EINVAL;
857 if (!optstr)
858 return 0;
859 return mnt_optstr_prepend_option(&fs->attrs, optstr, NULL);
860}
861
862
863/**
864 * mnt_fs_get_freq:
865 * @fs: fstab/mtab/mountinfo entry pointer
866 *
867 * Returns: dump frequency in days.
868 */
869int mnt_fs_get_freq(struct libmnt_fs *fs)
870{
871 assert(fs);
872 return fs ? fs->freq : 0;
873}
874
875/**
876 * mnt_fs_set_freq:
877 * @fs: fstab/mtab entry pointer
878 * @freq: dump frequency in days
879 *
880 * Returns: 0 on success or negative number in case of error.
881 */
882int mnt_fs_set_freq(struct libmnt_fs *fs, int freq)
883{
884 assert(fs);
885 if (!fs)
886 return -EINVAL;
887 fs->freq = freq;
888 return 0;
889}
890
891/**
892 * mnt_fs_get_passno:
893 * @fs: fstab/mtab entry pointer
894 *
895 * Returns: "pass number on parallel fsck".
896 */
897int mnt_fs_get_passno(struct libmnt_fs *fs)
898{
899 assert(fs);
900 return fs ? fs->passno: 0;
901}
902
903/**
904 * mnt_fs_set_passno:
905 * @fs: fstab/mtab entry pointer
906 * @passno: pass number
907 *
908 * Returns: 0 on success or negative number in case of error.
909 */
910int mnt_fs_set_passno(struct libmnt_fs *fs, int passno)
911{
912 assert(fs);
913 if (!fs)
914 return -EINVAL;
915 fs->passno = passno;
916 return 0;
917}
918
919/**
920 * mnt_fs_get_root:
921 * @fs: /proc/self/mountinfo entry
922 *
923 * Returns: root of the mount within the filesystem or NULL
924 */
925const char *mnt_fs_get_root(struct libmnt_fs *fs)
926{
927 assert(fs);
928 return fs ? fs->root : NULL;
929}
930
931/**
932 * mnt_fs_set_root:
933 * @fs: mountinfo entry
934 * @root: path
935 *
936 * Returns: 0 on success or negative number in case of error.
937 */
938int mnt_fs_set_root(struct libmnt_fs *fs, const char *root)
939{
940 char *p = NULL;
941
942 assert(fs);
943 if (!fs)
944 return -EINVAL;
945 if (root) {
946 p = strdup(root);
947 if (!p)
948 return -ENOMEM;
949 }
950 free(fs->root);
951 fs->root = p;
952 return 0;
953}
954
955/**
956 * mnt_fs_get_bindsrc:
957 * @fs: /run/mount/utab entry
958 *
959 * Returns: full path that was used for mount(2) on MS_BIND
960 */
961const char *mnt_fs_get_bindsrc(struct libmnt_fs *fs)
962{
963 assert(fs);
964 return fs ? fs->bindsrc : NULL;
965}
966
967/**
968 * mnt_fs_set_bindsrc:
969 * @fs: filesystem
970 * @src: path
971 *
972 * Returns: 0 on success or negative number in case of error.
973 */
974int mnt_fs_set_bindsrc(struct libmnt_fs *fs, const char *src)
975{
976 char *p = NULL;
977
978 assert(fs);
979 if (!fs)
980 return -EINVAL;
981 if (src) {
982 p = strdup(src);
983 if (!p)
984 return -ENOMEM;
985 }
986 free(fs->bindsrc);
987 fs->bindsrc = p;
988 return 0;
989}
990
991/**
992 * mnt_fs_get_id:
993 * @fs: /proc/self/mountinfo entry
994 *
995 * Returns: mount ID (unique identifier of the mount) or negative number in case of error.
996 */
997int mnt_fs_get_id(struct libmnt_fs *fs)
998{
999 assert(fs);
1000 return fs ? fs->id : -EINVAL;
1001}
1002
1003/**
1004 * mnt_fs_get_parent_id:
1005 * @fs: /proc/self/mountinfo entry
1006 *
1007 * Returns: parent mount ID or negative number in case of error.
1008 */
1009int mnt_fs_get_parent_id(struct libmnt_fs *fs)
1010{
1011 assert(fs);
1012 return fs ? fs->parent : -EINVAL;
1013}
1014
1015/**
1016 * mnt_fs_get_devno:
1017 * @fs: /proc/self/mountinfo entry
1018 *
1019 * Returns: value of st_dev for files on filesystem or 0 in case of error.
1020 */
1021dev_t mnt_fs_get_devno(struct libmnt_fs *fs)
1022{
1023 assert(fs);
1024 return fs ? fs->devno : 0;
1025}
1026
1027/**
1028 * mnt_fs_get_option:
1029 * @fs: fstab/mtab/mountinfo entry pointer
1030 * @name: option name
1031 * @value: returns pointer to the begin of the value (e.g. name=VALUE) or NULL
1032 * @valsz: returns size of options value or 0
1033 *
1034 * Returns: 0 on success, 1 when not found the @name or negative number in case of error.
1035 */
1036int mnt_fs_get_option(struct libmnt_fs *fs, const char *name,
1037 char **value, size_t *valsz)
1038{
1039 char rc = 1;
1040
1041 if (fs->fs_optstr)
1042 rc = mnt_optstr_get_option(fs->fs_optstr, name, value, valsz);
1043 if (rc == 1 && fs->vfs_optstr)
1044 rc = mnt_optstr_get_option(fs->vfs_optstr, name, value, valsz);
1045 if (rc == 1 && fs->user_optstr)
1046 rc = mnt_optstr_get_option(fs->user_optstr, name, value, valsz);
1047 return rc;
1048}
1049
1050/**
1051 * mnt_fs_get_attribute:
1052 * @fs: fstab/mtab/mountinfo entry pointer
1053 * @name: option name
1054 * @value: returns pointer to the begin of the value (e.g. name=VALUE) or NULL
1055 * @valsz: returns size of options value or 0
1056 *
1057 * Returns: 0 on success, 1 when not found the @name or negative number in case of error.
1058 */
1059int mnt_fs_get_attribute(struct libmnt_fs *fs, const char *name,
1060 char **value, size_t *valsz)
1061{
1062 char rc = 1;
1063
1064 if (fs->attrs)
1065 rc = mnt_optstr_get_option(fs->attrs, name, value, valsz);
1066 return rc;
1067}
1068
1069/**
1070 * mnt_fs_match_target:
1071 * @fs: filesystem
1072 * @target: mountpoint path
1073 * @cache: tags/paths cache or NULL
1074 *
1075 * Possible are three attempts:
1076 * 1) compare @target with @fs->target
1077 * 2) realpath(@target) with @fs->target
1078 * 3) realpath(@target) with realpath(@fs->target).
1079 *
1080 * The 2nd and 3rd attempts are not performed when @cache is NULL.
1081 *
1082 * Returns: 1 if @fs target is equal to @target else 0.
1083 */
1084int mnt_fs_match_target(struct libmnt_fs *fs, const char *target, struct libmnt_cache *cache)
1085{
1086 int rc = 0;
1087
1088 if (!fs || !target || !fs->target)
1089 return 0;
1090
1091 /* 1) native paths */
1092 rc = !strcmp(target, fs->target);
1093
1094 if (!rc && cache) {
1095 /* 2) - canonicalized and non-canonicalized */
1096 char *cn = mnt_resolve_path(target, cache);
1097 rc = (cn && strcmp(cn, fs->target) == 0);
1098
1099 /* 3) - canonicalized and canonicalized */
1100 if (!rc && cn) {
1101 char *tcn = mnt_resolve_path(fs->target, cache);
1102 rc = (tcn && strcmp(cn, tcn) == 0);
1103 }
1104 }
1105
1106 return rc;
1107}
1108
1109/**
1110 * mnt_fs_match_source:
1111 * @fs: filesystem
1112 * @source: tag or path (device or so) or NULL
1113 * @cache: tags/paths cache or NULL
1114 *
1115 * Possible are four attempts:
1116 * 1) compare @source with @fs->source
1117 * 2) compare realpath(@source) with @fs->source
1118 * 3) compare realpath(@source) with realpath(@fs->source)
1119 * 4) compare realpath(@source) with evaluated tag from @fs->source
1120 *
1121 * The 2nd, 3rd and 4th attempts are not performed when @cache is NULL. The
1122 * 2nd and 3rd attempts are not performed if @fs->source is tag.
1123 *
1124 * Note that valid source path is NULL; the libmount uses NULL instead of
1125 * "none". The "none" is used in /proc/{mounts,self/mountninfo} for pseudo
1126 * filesystems.
1127 *
1128 * Returns: 1 if @fs source is equal to @source else 0.
1129 */
1130int mnt_fs_match_source(struct libmnt_fs *fs, const char *source, struct libmnt_cache *cache)
1131{
1132 char *cn;
1133 const char *src, *t, *v;
1134
1135 if (!fs)
1136 return 0;
1137
1138 /* undefined source -- "none" in /proc */
1139 if (source == NULL && fs->source == NULL)
1140 return 1;
1141
1142 if (source == NULL || fs->source == NULL)
1143 return 0;
1144
1145 /* 1) native paths/tags */
1146 if (streq_except_trailing_slash(source, fs->source))
1147 return 1;
1148
1149 if (!cache)
1150 return 0;
1151 if (fs->flags & (MNT_FS_NET | MNT_FS_PSEUDO))
1152 return 0;
1153
1154 cn = mnt_resolve_spec(source, cache);
1155 if (!cn)
1156 return 0;
1157
1158 /* 2) canonicalized and native */
1159 src = mnt_fs_get_srcpath(fs);
1160 if (src && streq_except_trailing_slash(cn, src))
1161 return 1;
1162
1163 /* 3) canonicalized and canonicalized */
1164 if (src) {
1165 src = mnt_resolve_path(src, cache);
1166 if (src && !strcmp(cn, src))
1167 return 1;
1168 }
1169 if (src || mnt_fs_get_tag(fs, &t, &v))
1170 /* src path does not match and tag is not defined */
1171 return 0;
1172
1173 /* read @source's tags to the cache */
1174 if (mnt_cache_read_tags(cache, cn) < 0) {
1175 if (errno == EACCES) {
1176 /* we don't have permissions to read TAGs from
1177 * @source, but can translate @fs tag to devname.
1178 *
1179 * (because libblkid uses udev symlinks and this is
1180 * accessible for non-root uses)
1181 */
1182 char *x = mnt_resolve_tag(t, v, cache);
1183 if (x && !strcmp(x, cn))
1184 return 1;
1185 }
1186 return 0;
1187 }
1188
1189 /* 4) has the @source a tag that matches with tag from @fs ? */
1190 if (mnt_cache_device_has_tag(cache, cn, t, v))
1191 return 1;
1192
1193 return 0;
1194}
1195
1196/**
1197 * mnt_fs_match_fstype:
1198 * @fs: filesystem
1199 * @types: filesystem name or comma delimited list of filesystems
1200 *
1201 * For more details see mnt_match_fstype().
1202 *
1203 * Returns: 1 if @fs type is matching to @types else 0. The function returns
1204 * 0 when types is NULL.
1205 */
1206int mnt_fs_match_fstype(struct libmnt_fs *fs, const char *types)
1207{
1208 return mnt_match_fstype(fs->fstype, types);
1209}
1210
1211/**
1212 * mnt_fs_match_options:
1213 * @fs: filesystem
1214 * @options: comma delimited list of options (and nooptions)
1215 *
1216 * For more details see mnt_match_options().
1217 *
1218 * Returns: 1 if @fs type is matching to @options else 0. The function returns
1219 * 0 when types is NULL.
1220 */
1221int mnt_fs_match_options(struct libmnt_fs *fs, const char *options)
1222{
1223 return mnt_match_options(mnt_fs_get_options(fs), options);
1224}
1225
1226/**
1227 * mnt_fs_print_debug
1228 * @fs: fstab/mtab/mountinfo entry
1229 * @file: file stream
1230 *
1231 * Returns: 0 on success or negative number in case of error.
1232 */
1233int mnt_fs_print_debug(struct libmnt_fs *fs, FILE *file)
1234{
1235 if (!fs)
1236 return -EINVAL;
1237 fprintf(file, "------ fs: %p\n", fs);
1238 fprintf(file, "source: %s\n", mnt_fs_get_source(fs));
1239 fprintf(file, "target: %s\n", mnt_fs_get_target(fs));
1240 fprintf(file, "fstype: %s\n", mnt_fs_get_fstype(fs));
1241
1242 if (mnt_fs_get_options(fs))
1243 fprintf(file, "optstr: %s\n", mnt_fs_get_options(fs));
1244 if (mnt_fs_get_vfs_options(fs))
1245 fprintf(file, "VFS-optstr: %s\n", mnt_fs_get_vfs_options(fs));
1246 if (mnt_fs_get_fs_options(fs))
1247 fprintf(file, "FS-opstr: %s\n", mnt_fs_get_fs_options(fs));
1248 if (mnt_fs_get_user_options(fs))
1249 fprintf(file, "user-optstr: %s\n", mnt_fs_get_user_options(fs));
1250 if (mnt_fs_get_attributes(fs))
1251 fprintf(file, "attributes: %s\n", mnt_fs_get_attributes(fs));
1252
1253 if (mnt_fs_get_root(fs))
1254 fprintf(file, "root: %s\n", mnt_fs_get_root(fs));
1255 if (mnt_fs_get_bindsrc(fs))
1256 fprintf(file, "bindsrc: %s\n", mnt_fs_get_bindsrc(fs));
1257 if (mnt_fs_get_freq(fs))
1258 fprintf(file, "freq: %d\n", mnt_fs_get_freq(fs));
1259 if (mnt_fs_get_passno(fs))
1260 fprintf(file, "pass: %d\n", mnt_fs_get_passno(fs));
1261 if (mnt_fs_get_id(fs))
1262 fprintf(file, "id: %d\n", mnt_fs_get_id(fs));
1263 if (mnt_fs_get_parent_id(fs))
1264 fprintf(file, "parent: %d\n", mnt_fs_get_parent_id(fs));
1265 if (mnt_fs_get_devno(fs))
1266 fprintf(file, "devno: %d:%d\n", major(mnt_fs_get_devno(fs)),
1267 minor(mnt_fs_get_devno(fs)));
1268 return 0;
1269}
1270
1271/**
1272 * mnt_free_mntent:
1273 * @mnt: mount entry
1274 *
1275 * Deallocates "mntent.h" mount entry.
1276 */
1277void mnt_free_mntent(struct mntent *mnt)
1278{
1279 if (mnt) {
1280 free(mnt->mnt_fsname);
1281 free(mnt->mnt_dir);
1282 free(mnt->mnt_type);
1283 free(mnt->mnt_opts);
1284 free(mnt);
1285 }
1286}
1287
1288/**
1289 * mnt_fs_to_mntent:
1290 * @fs: filesystem
1291 * @mnt: mount description (as described in mntent.h)
1292 *
1293 * Copies information from @fs to struct mntent @mnt. If @mnt is already set
1294 * then the struct mntent items are reallocated and updated. See also
1295 * mnt_free_mntent().
1296 *
1297 * Returns: 0 on success and negative number in case of error.
1298 */
1299int mnt_fs_to_mntent(struct libmnt_fs *fs, struct mntent **mnt)
1300{
1301 int rc;
1302 struct mntent *m;
1303
1304 if (!fs || !mnt)
1305 return -EINVAL;
1306
1307 m = *mnt;
1308 if (!m) {
1309 m = calloc(1, sizeof(*m));
1310 if (!m)
1311 return -ENOMEM;
1312 }
1313
1314 if ((rc = update_str(&m->mnt_fsname, mnt_fs_get_source(fs))))
1315 goto err;
1316 if ((rc = update_str(&m->mnt_dir, mnt_fs_get_target(fs))))
1317 goto err;
1318 if ((rc = update_str(&m->mnt_type, mnt_fs_get_fstype(fs))))
1319 goto err;
1320
1321 errno = 0;
1322 m->mnt_opts = mnt_fs_strdup_options(fs);
1323 if (!m->mnt_opts && errno) {
1324 rc = -errno;
1325 goto err;
1326 }
1327
1328 m->mnt_freq = mnt_fs_get_freq(fs);
1329 m->mnt_passno = mnt_fs_get_passno(fs);
1330
1331 if (!m->mnt_fsname) {
1332 m->mnt_fsname = strdup("none");
1333 if (!m->mnt_fsname)
1334 goto err;
1335 }
1336 *mnt = m;
1337
1338 return 0;
1339err:
1340 if (m != *mnt)
1341 mnt_free_mntent(m);
1342 return rc;
1343}