]> git.ipfire.org Git - thirdparty/util-linux.git/blob - libmount/src/fs.c
libmount: consolidate MNT_FS_* code
[thirdparty/util-linux.git] / libmount / src / fs.c
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 */
26 struct 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 */
43 void 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 */
73 void mnt_reset_fs(struct libmnt_fs *fs)
74 {
75 if (fs)
76 memset(fs, 0, sizeof(*fs));
77 }
78
79 static 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
101 static 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 */
125 struct 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;
172 err:
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 */
185 struct 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;
227 err:
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 */
239 void *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 */
253 int 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 */
274 const 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 */
293 const 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 */
301 int __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 */
337 int 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 */
389 int 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 */
406 const 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 */
421 int 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
440 static int mnt_fs_get_flags(struct libmnt_fs *fs)
441 {
442 return fs ? fs->flags : 0;
443 }
444
445 /**
446 * mnt_fs_is_kernel:
447 * @fs: filesystem
448 *
449 * Returns: 1 if the filesystem description is read from kernel e.g. /proc/mounts.
450 */
451 int mnt_fs_is_kernel(struct libmnt_fs *fs)
452 {
453 return mnt_fs_get_flags(fs) & MNT_FS_KERNEL;
454 }
455
456 /**
457 * mnt_fs_is_swaparea:
458 * @fs: filesystem
459 *
460 * Returns: 1 if the filesystem uses "swap" as a type
461 */
462 int mnt_fs_is_swaparea(struct libmnt_fs *fs)
463 {
464 return mnt_fs_get_flags(fs) & MNT_FS_SWAP;
465 }
466
467 /**
468 * mnt_fs_is_pseudofs:
469 * @fs: filesystem
470 *
471 * Returns: 1 if the filesystem is a pseudo fs type (proc, cgroups)
472 */
473 int mnt_fs_is_pseudo(struct libmnt_fs *fs)
474 {
475 return mnt_fs_get_flags(fs) & MNT_FS_PSEUDO;
476 }
477
478 /**
479 * mnt_fs_is_netfs:
480 * @fs: filesystem
481 *
482 * Returns: 1 if the filesystem is a network filesystem
483 */
484 int mnt_fs_is_netfs(struct libmnt_fs *fs)
485 {
486 return mnt_fs_get_flags(fs) & MNT_FS_NET;
487 }
488
489 /**
490 * mnt_fs_get_fstype:
491 * @fs: fstab/mtab/mountinfo entry pointer
492 *
493 * Returns: pointer to filesystem type.
494 */
495 const char *mnt_fs_get_fstype(struct libmnt_fs *fs)
496 {
497 assert(fs);
498 return fs ? fs->fstype : NULL;
499 }
500
501 /* Used by struct libmnt_file parser only */
502 int __mnt_fs_set_fstype_ptr(struct libmnt_fs *fs, char *fstype)
503 {
504 assert(fs);
505
506 if (fstype != fs->fstype)
507 free(fs->fstype);
508
509 fs->fstype = fstype;
510 fs->flags &= ~MNT_FS_PSEUDO;
511 fs->flags &= ~MNT_FS_NET;
512 fs->flags &= ~MNT_FS_SWAP;
513
514 /* save info about pseudo filesystems */
515 if (fs->fstype) {
516 if (mnt_fstype_is_pseudofs(fs->fstype))
517 fs->flags |= MNT_FS_PSEUDO;
518 else if (mnt_fstype_is_netfs(fs->fstype))
519 fs->flags |= MNT_FS_NET;
520 else if (!strcmp(fs->fstype, "swap"))
521 fs->flags |= MNT_FS_SWAP;
522 }
523 return 0;
524 }
525
526 /**
527 * mnt_fs_set_fstype:
528 * @fs: fstab/mtab/mountinfo entry
529 * @fstype: filesystem type
530 *
531 * This function creates a private copy (strdup()) of @fstype.
532 *
533 * Returns: 0 on success or negative number in case of error.
534 */
535 int mnt_fs_set_fstype(struct libmnt_fs *fs, const char *fstype)
536 {
537 char *p = NULL;
538
539 if (!fs)
540 return -EINVAL;
541 if (fstype) {
542 p = strdup(fstype);
543 if (!p)
544 return -ENOMEM;
545 }
546 return __mnt_fs_set_fstype_ptr(fs, p);
547 }
548
549 /*
550 * Merges @vfs and @fs options strings into a new string.
551 * This function cares about 'ro/rw' options. The 'ro' is
552 * always used if @vfs or @fs is read-only.
553 * For example:
554 *
555 * mnt_merge_optstr("rw,noexec", "ro,journal=update")
556 *
557 * returns: "ro,noexec,journal=update"
558 *
559 * mnt_merge_optstr("rw,noexec", "rw,journal=update")
560 *
561 * returns: "rw,noexec,journal=update"
562 */
563 static char *merge_optstr(const char *vfs, const char *fs)
564 {
565 char *res, *p;
566 size_t sz;
567 int ro = 0, rw = 0;
568
569 if (!vfs && !fs)
570 return NULL;
571 if (!vfs || !fs)
572 return strdup(fs ? fs : vfs);
573 if (!strcmp(vfs, fs))
574 return strdup(vfs); /* e.g. "aaa" and "aaa" */
575
576 /* leave space for leading "r[ow],", "," and trailing zero */
577 sz = strlen(vfs) + strlen(fs) + 5;
578 res = malloc(sz);
579 if (!res)
580 return NULL;
581 p = res + 3; /* make a room for rw/ro flag */
582
583 snprintf(p, sz - 3, "%s,%s", vfs, fs);
584
585 /* remove 'rw' flags */
586 rw += !mnt_optstr_remove_option(&p, "rw"); /* from vfs */
587 rw += !mnt_optstr_remove_option(&p, "rw"); /* from fs */
588
589 /* remove 'ro' flags if necessary */
590 if (rw != 2) {
591 ro += !mnt_optstr_remove_option(&p, "ro");
592 if (ro + rw < 2)
593 ro += !mnt_optstr_remove_option(&p, "ro");
594 }
595
596 if (!strlen(p))
597 memcpy(res, ro ? "ro" : "rw", 3);
598 else
599 memcpy(res, ro ? "ro," : "rw,", 3);
600 return res;
601 }
602
603 /**
604 * mnt_fs_strdup_options:
605 * @fs: fstab/mtab/mountinfo entry pointer
606 *
607 * Merges all mount options (VFS, FS and userspace) to the one options string
608 * and returns the result. This function does not modigy @fs.
609 *
610 * Returns: pointer to string (can be freed by free(3)) or NULL in case of error.
611 */
612 char *mnt_fs_strdup_options(struct libmnt_fs *fs)
613 {
614 char *res;
615
616 assert(fs);
617
618 errno = 0;
619
620 if (fs->optstr)
621 return strdup(fs->optstr);
622
623 res = merge_optstr(fs->vfs_optstr, fs->fs_optstr);
624 if (!res && errno)
625 return NULL;
626 if (fs->user_optstr) {
627 if (mnt_optstr_append_option(&res, fs->user_optstr, NULL)) {
628 free(res);
629 res = NULL;
630 }
631 }
632 return res;
633 }
634
635 /**
636 * mnt_fs_get_options:
637 * @fs: fstab/mtab/mountinfo entry pointer
638 *
639 * Returns: pointer to string or NULL in case of error.
640 */
641 const char *mnt_fs_get_options(struct libmnt_fs *fs)
642 {
643 assert(fs);
644 return fs ? fs->optstr : NULL;
645 }
646
647
648 /**
649 * mnt_fs_set_options:
650 * @fs: fstab/mtab/mountinfo entry pointer
651 * @optstr: options string
652 *
653 * Splits @optstr to VFS, FS and userspace mount options and update relevat
654 * parts of @fs.
655 *
656 * Returns: 0 on success, or negative number icase of error.
657 */
658 int mnt_fs_set_options(struct libmnt_fs *fs, const char *optstr)
659 {
660 char *v = NULL, *f = NULL, *u = NULL, *n = NULL;
661
662 assert(fs);
663
664 if (!fs)
665 return -EINVAL;
666 if (optstr) {
667 int rc = mnt_split_optstr(optstr, &u, &v, &f, 0, 0);
668 if (rc)
669 return rc;
670 n = strdup(optstr);
671 if (!n)
672 return -ENOMEM;
673 }
674
675 free(fs->fs_optstr);
676 free(fs->vfs_optstr);
677 free(fs->user_optstr);
678 free(fs->optstr);
679
680 fs->fs_optstr = f;
681 fs->vfs_optstr = v;
682 fs->user_optstr = u;
683 fs->optstr = n;
684
685 return 0;
686 }
687
688 /**
689 * mnt_fs_append_options:
690 * @fs: fstab/mtab/mountinfo entry
691 * @optstr: mount options
692 *
693 * Parses (splits) @optstr and appends results to VFS, FS and userspace lists
694 * of options.
695 *
696 * If @optstr is NULL then @fs is not modified and 0 is returned.
697 *
698 * Returns: 0 on success or negative number in case of error.
699 */
700 int mnt_fs_append_options(struct libmnt_fs *fs, const char *optstr)
701 {
702 char *v = NULL, *f = NULL, *u = NULL;
703 int rc;
704
705 assert(fs);
706
707 if (!fs)
708 return -EINVAL;
709 if (!optstr)
710 return 0;
711
712 rc = mnt_split_optstr((char *) optstr, &u, &v, &f, 0, 0);
713 if (!rc && v)
714 rc = mnt_optstr_append_option(&fs->vfs_optstr, v, NULL);
715 if (!rc && f)
716 rc = mnt_optstr_append_option(&fs->fs_optstr, f, NULL);
717 if (!rc && u)
718 rc = mnt_optstr_append_option(&fs->user_optstr, u, NULL);
719 if (!rc)
720 rc = mnt_optstr_append_option(&fs->optstr, optstr, NULL);
721
722 free(v);
723 free(f);
724 free(u);
725
726 return rc;
727 }
728
729 /**
730 * mnt_fs_prepend_options:
731 * @fs: fstab/mtab/mountinfo entry
732 * @optstr: mount options
733 *
734 * Parses (splits) @optstr and prepands results to VFS, FS and userspace lists
735 * of options.
736 *
737 * If @optstr is NULL then @fs is not modified and 0 is returned.
738 *
739 * Returns: 0 on success or negative number in case of error.
740 */
741 int mnt_fs_prepend_options(struct libmnt_fs *fs, const char *optstr)
742 {
743 char *v = NULL, *f = NULL, *u = NULL;
744 int rc;
745
746 assert(fs);
747
748 if (!fs)
749 return -EINVAL;
750 if (!optstr)
751 return 0;
752
753 rc = mnt_split_optstr((char *) optstr, &u, &v, &f, 0, 0);
754 if (!rc && v)
755 rc = mnt_optstr_prepend_option(&fs->vfs_optstr, v, NULL);
756 if (!rc && f)
757 rc = mnt_optstr_prepend_option(&fs->fs_optstr, f, NULL);
758 if (!rc && u)
759 rc = mnt_optstr_prepend_option(&fs->user_optstr, u, NULL);
760 if (!rc)
761 rc = mnt_optstr_prepend_option(&fs->optstr, optstr, NULL);
762
763 free(v);
764 free(f);
765 free(u);
766
767 return rc;
768 }
769
770 /*
771 * mnt_fs_get_fs_options:
772 * @fs: fstab/mtab/mountinfo entry pointer
773 *
774 * Returns: pointer to superblock (fs-depend) mount option string or NULL.
775 */
776 const char *mnt_fs_get_fs_options(struct libmnt_fs *fs)
777 {
778 assert(fs);
779 return fs ? fs->fs_optstr : NULL;
780 }
781
782 /**
783 * mnt_fs_get_vfs_options:
784 * @fs: fstab/mtab entry pointer
785 *
786 * Returns: pointer to fs-independent (VFS) mount option string or NULL.
787 */
788 const char *mnt_fs_get_vfs_options(struct libmnt_fs *fs)
789 {
790 assert(fs);
791 return fs ? fs->vfs_optstr : NULL;
792 }
793
794 /**
795 * mnt_fs_get_user_options:
796 * @fs: fstab/mtab entry pointer
797 *
798 * Returns: pointer to userspace mount option string or NULL.
799 */
800 const char *mnt_fs_get_user_options(struct libmnt_fs *fs)
801 {
802 assert(fs);
803 return fs ? fs->user_optstr : NULL;
804 }
805
806 /**
807 * mnt_fs_get_attributes:
808 * @fs: fstab/mtab entry pointer
809 *
810 * Returns: pointer to attributes string or NULL.
811 */
812 const char *mnt_fs_get_attributes(struct libmnt_fs *fs)
813 {
814 assert(fs);
815 return fs ? fs->attrs : NULL;
816 }
817
818 /**
819 * mnt_fs_set_attributes:
820 * @fs: fstab/mtab/mountinfo entry
821 * @optstr: options string
822 *
823 * Sets mount attributes. The attributes are mount(2) and mount(8) independent
824 * options, these options are not send to kernel and are not interpreted by
825 * libmount. The attributes are stored in /run/mount/utab only.
826 *
827 * The atrtributes are managed by libmount in userspace only. It's possible
828 * that information stored in userspace will not be available for libmount
829 * after CLONE_FS unshare. Be carefull, and don't use attributes if possible.
830 *
831 * Returns: 0 on success or negative number in case of error.
832 */
833 int mnt_fs_set_attributes(struct libmnt_fs *fs, const char *optstr)
834 {
835 char *p = NULL;
836
837 if (!fs)
838 return -EINVAL;
839 if (optstr) {
840 p = strdup(optstr);
841 if (!p)
842 return -ENOMEM;
843 }
844 free(fs->attrs);
845 fs->attrs = p;
846
847 return 0;
848 }
849
850 /**
851 * mnt_fs_append_attributes
852 * @fs: fstab/mtab/mountinfo entry
853 * @optstr: options string
854 *
855 * Appends mount attributes. (See mnt_fs_set_attributes()).
856 *
857 * Returns: 0 on success or negative number in case of error.
858 */
859 int mnt_fs_append_attributes(struct libmnt_fs *fs, const char *optstr)
860 {
861 if (!fs)
862 return -EINVAL;
863 if (!optstr)
864 return 0;
865 return mnt_optstr_append_option(&fs->attrs, optstr, NULL);
866 }
867
868 /**
869 * mnt_fs_prepend_attributes
870 * @fs: fstab/mtab/mountinfo entry
871 * @optstr: options string
872 *
873 * Prepends mount attributes. (See mnt_fs_set_attributes()).
874 *
875 * Returns: 0 on success or negative number in case of error.
876 */
877 int mnt_fs_prepend_attributes(struct libmnt_fs *fs, const char *optstr)
878 {
879 if (!fs)
880 return -EINVAL;
881 if (!optstr)
882 return 0;
883 return mnt_optstr_prepend_option(&fs->attrs, optstr, NULL);
884 }
885
886
887 /**
888 * mnt_fs_get_freq:
889 * @fs: fstab/mtab/mountinfo entry pointer
890 *
891 * Returns: dump frequency in days.
892 */
893 int mnt_fs_get_freq(struct libmnt_fs *fs)
894 {
895 assert(fs);
896 return fs ? fs->freq : 0;
897 }
898
899 /**
900 * mnt_fs_set_freq:
901 * @fs: fstab/mtab entry pointer
902 * @freq: dump frequency in days
903 *
904 * Returns: 0 on success or negative number in case of error.
905 */
906 int mnt_fs_set_freq(struct libmnt_fs *fs, int freq)
907 {
908 assert(fs);
909 if (!fs)
910 return -EINVAL;
911 fs->freq = freq;
912 return 0;
913 }
914
915 /**
916 * mnt_fs_get_passno:
917 * @fs: fstab/mtab entry pointer
918 *
919 * Returns: "pass number on parallel fsck".
920 */
921 int mnt_fs_get_passno(struct libmnt_fs *fs)
922 {
923 assert(fs);
924 return fs ? fs->passno: 0;
925 }
926
927 /**
928 * mnt_fs_set_passno:
929 * @fs: fstab/mtab entry pointer
930 * @passno: pass number
931 *
932 * Returns: 0 on success or negative number in case of error.
933 */
934 int mnt_fs_set_passno(struct libmnt_fs *fs, int passno)
935 {
936 assert(fs);
937 if (!fs)
938 return -EINVAL;
939 fs->passno = passno;
940 return 0;
941 }
942
943 /**
944 * mnt_fs_get_root:
945 * @fs: /proc/self/mountinfo entry
946 *
947 * Returns: root of the mount within the filesystem or NULL
948 */
949 const char *mnt_fs_get_root(struct libmnt_fs *fs)
950 {
951 assert(fs);
952 return fs ? fs->root : NULL;
953 }
954
955 /**
956 * mnt_fs_set_root:
957 * @fs: mountinfo entry
958 * @root: path
959 *
960 * Returns: 0 on success or negative number in case of error.
961 */
962 int mnt_fs_set_root(struct libmnt_fs *fs, const char *root)
963 {
964 char *p = NULL;
965
966 assert(fs);
967 if (!fs)
968 return -EINVAL;
969 if (root) {
970 p = strdup(root);
971 if (!p)
972 return -ENOMEM;
973 }
974 free(fs->root);
975 fs->root = p;
976 return 0;
977 }
978
979 /**
980 * mnt_fs_get_bindsrc:
981 * @fs: /run/mount/utab entry
982 *
983 * Returns: full path that was used for mount(2) on MS_BIND
984 */
985 const char *mnt_fs_get_bindsrc(struct libmnt_fs *fs)
986 {
987 assert(fs);
988 return fs ? fs->bindsrc : NULL;
989 }
990
991 /**
992 * mnt_fs_set_bindsrc:
993 * @fs: filesystem
994 * @src: path
995 *
996 * Returns: 0 on success or negative number in case of error.
997 */
998 int mnt_fs_set_bindsrc(struct libmnt_fs *fs, const char *src)
999 {
1000 char *p = NULL;
1001
1002 assert(fs);
1003 if (!fs)
1004 return -EINVAL;
1005 if (src) {
1006 p = strdup(src);
1007 if (!p)
1008 return -ENOMEM;
1009 }
1010 free(fs->bindsrc);
1011 fs->bindsrc = p;
1012 return 0;
1013 }
1014
1015 /**
1016 * mnt_fs_get_id:
1017 * @fs: /proc/self/mountinfo entry
1018 *
1019 * Returns: mount ID (unique identifier of the mount) or negative number in case of error.
1020 */
1021 int mnt_fs_get_id(struct libmnt_fs *fs)
1022 {
1023 assert(fs);
1024 return fs ? fs->id : -EINVAL;
1025 }
1026
1027 /**
1028 * mnt_fs_get_parent_id:
1029 * @fs: /proc/self/mountinfo entry
1030 *
1031 * Returns: parent mount ID or negative number in case of error.
1032 */
1033 int mnt_fs_get_parent_id(struct libmnt_fs *fs)
1034 {
1035 assert(fs);
1036 return fs ? fs->parent : -EINVAL;
1037 }
1038
1039 /**
1040 * mnt_fs_get_devno:
1041 * @fs: /proc/self/mountinfo entry
1042 *
1043 * Returns: value of st_dev for files on filesystem or 0 in case of error.
1044 */
1045 dev_t mnt_fs_get_devno(struct libmnt_fs *fs)
1046 {
1047 assert(fs);
1048 return fs ? fs->devno : 0;
1049 }
1050
1051 /**
1052 * mnt_fs_get_option:
1053 * @fs: fstab/mtab/mountinfo entry pointer
1054 * @name: option name
1055 * @value: returns pointer to the begin of the value (e.g. name=VALUE) or NULL
1056 * @valsz: returns size of options value or 0
1057 *
1058 * Returns: 0 on success, 1 when not found the @name or negative number in case of error.
1059 */
1060 int mnt_fs_get_option(struct libmnt_fs *fs, const char *name,
1061 char **value, size_t *valsz)
1062 {
1063 char rc = 1;
1064
1065 if (fs->fs_optstr)
1066 rc = mnt_optstr_get_option(fs->fs_optstr, name, value, valsz);
1067 if (rc == 1 && fs->vfs_optstr)
1068 rc = mnt_optstr_get_option(fs->vfs_optstr, name, value, valsz);
1069 if (rc == 1 && fs->user_optstr)
1070 rc = mnt_optstr_get_option(fs->user_optstr, name, value, valsz);
1071 return rc;
1072 }
1073
1074 /**
1075 * mnt_fs_get_attribute:
1076 * @fs: fstab/mtab/mountinfo entry pointer
1077 * @name: option name
1078 * @value: returns pointer to the begin of the value (e.g. name=VALUE) or NULL
1079 * @valsz: returns size of options value or 0
1080 *
1081 * Returns: 0 on success, 1 when not found the @name or negative number in case of error.
1082 */
1083 int mnt_fs_get_attribute(struct libmnt_fs *fs, const char *name,
1084 char **value, size_t *valsz)
1085 {
1086 char rc = 1;
1087
1088 if (fs->attrs)
1089 rc = mnt_optstr_get_option(fs->attrs, name, value, valsz);
1090 return rc;
1091 }
1092
1093 /**
1094 * mnt_fs_match_target:
1095 * @fs: filesystem
1096 * @target: mountpoint path
1097 * @cache: tags/paths cache or NULL
1098 *
1099 * Possible are three attempts:
1100 * 1) compare @target with @fs->target
1101 * 2) realpath(@target) with @fs->target
1102 * 3) realpath(@target) with realpath(@fs->target).
1103 *
1104 * The 2nd and 3rd attempts are not performed when @cache is NULL.
1105 *
1106 * Returns: 1 if @fs target is equal to @target else 0.
1107 */
1108 int mnt_fs_match_target(struct libmnt_fs *fs, const char *target,
1109 struct libmnt_cache *cache)
1110 {
1111 int rc = 0;
1112
1113 if (!fs || !target || !fs->target)
1114 return 0;
1115
1116 /* 1) native paths */
1117 rc = !strcmp(target, fs->target);
1118
1119 if (!rc && cache) {
1120 /* 2) - canonicalized and non-canonicalized */
1121 char *cn = mnt_resolve_path(target, cache);
1122 rc = (cn && strcmp(cn, fs->target) == 0);
1123
1124 /* 3) - canonicalized and canonicalized */
1125 if (!rc && cn) {
1126 char *tcn = mnt_resolve_path(fs->target, cache);
1127 rc = (tcn && strcmp(cn, tcn) == 0);
1128 }
1129 }
1130
1131 return rc;
1132 }
1133
1134 /**
1135 * mnt_fs_match_source:
1136 * @fs: filesystem
1137 * @source: tag or path (device or so) or NULL
1138 * @cache: tags/paths cache or NULL
1139 *
1140 * Possible are four attempts:
1141 * 1) compare @source with @fs->source
1142 * 2) compare realpath(@source) with @fs->source
1143 * 3) compare realpath(@source) with realpath(@fs->source)
1144 * 4) compare realpath(@source) with evaluated tag from @fs->source
1145 *
1146 * The 2nd, 3rd and 4th attempts are not performed when @cache is NULL. The
1147 * 2nd and 3rd attempts are not performed if @fs->source is tag.
1148 *
1149 * Note that valid source path is NULL; the libmount uses NULL instead of
1150 * "none". The "none" is used in /proc/{mounts,self/mountninfo} for pseudo
1151 * filesystems.
1152 *
1153 * Returns: 1 if @fs source is equal to @source else 0.
1154 */
1155 int mnt_fs_match_source(struct libmnt_fs *fs, const char *source,
1156 struct libmnt_cache *cache)
1157 {
1158 char *cn;
1159 const char *src, *t, *v;
1160
1161 if (!fs)
1162 return 0;
1163
1164 /* undefined source -- "none" in /proc */
1165 if (source == NULL && fs->source == NULL)
1166 return 1;
1167
1168 if (source == NULL || fs->source == NULL)
1169 return 0;
1170
1171 /* 1) native paths/tags */
1172 if (streq_except_trailing_slash(source, fs->source))
1173 return 1;
1174
1175 if (!cache)
1176 return 0;
1177 if (fs->flags & (MNT_FS_NET | MNT_FS_PSEUDO))
1178 return 0;
1179
1180 cn = mnt_resolve_spec(source, cache);
1181 if (!cn)
1182 return 0;
1183
1184 /* 2) canonicalized and native */
1185 src = mnt_fs_get_srcpath(fs);
1186 if (src && streq_except_trailing_slash(cn, src))
1187 return 1;
1188
1189 /* 3) canonicalized and canonicalized */
1190 if (src) {
1191 src = mnt_resolve_path(src, cache);
1192 if (src && !strcmp(cn, src))
1193 return 1;
1194 }
1195 if (src || mnt_fs_get_tag(fs, &t, &v))
1196 /* src path does not match and tag is not defined */
1197 return 0;
1198
1199 /* read @source's tags to the cache */
1200 if (mnt_cache_read_tags(cache, cn) < 0) {
1201 if (errno == EACCES) {
1202 /* we don't have permissions to read TAGs from
1203 * @source, but can translate @fs tag to devname.
1204 *
1205 * (because libblkid uses udev symlinks and this is
1206 * accessible for non-root uses)
1207 */
1208 char *x = mnt_resolve_tag(t, v, cache);
1209 if (x && !strcmp(x, cn))
1210 return 1;
1211 }
1212 return 0;
1213 }
1214
1215 /* 4) has the @source a tag that matches with tag from @fs ? */
1216 if (mnt_cache_device_has_tag(cache, cn, t, v))
1217 return 1;
1218
1219 return 0;
1220 }
1221
1222 /**
1223 * mnt_fs_match_fstype:
1224 * @fs: filesystem
1225 * @types: filesystem name or comma delimited list of filesystems
1226 *
1227 * For more details see mnt_match_fstype().
1228 *
1229 * Returns: 1 if @fs type is matching to @types else 0. The function returns
1230 * 0 when types is NULL.
1231 */
1232 int mnt_fs_match_fstype(struct libmnt_fs *fs, const char *types)
1233 {
1234 return mnt_match_fstype(fs->fstype, types);
1235 }
1236
1237 /**
1238 * mnt_fs_match_options:
1239 * @fs: filesystem
1240 * @options: comma delimited list of options (and nooptions)
1241 *
1242 * For more details see mnt_match_options().
1243 *
1244 * Returns: 1 if @fs type is matching to @options else 0. The function returns
1245 * 0 when types is NULL.
1246 */
1247 int mnt_fs_match_options(struct libmnt_fs *fs, const char *options)
1248 {
1249 return mnt_match_options(mnt_fs_get_options(fs), options);
1250 }
1251
1252 /**
1253 * mnt_fs_print_debug
1254 * @fs: fstab/mtab/mountinfo entry
1255 * @file: file stream
1256 *
1257 * Returns: 0 on success or negative number in case of error.
1258 */
1259 int mnt_fs_print_debug(struct libmnt_fs *fs, FILE *file)
1260 {
1261 if (!fs)
1262 return -EINVAL;
1263 fprintf(file, "------ fs: %p\n", fs);
1264 fprintf(file, "source: %s\n", mnt_fs_get_source(fs));
1265 fprintf(file, "target: %s\n", mnt_fs_get_target(fs));
1266 fprintf(file, "fstype: %s\n", mnt_fs_get_fstype(fs));
1267
1268 if (mnt_fs_get_options(fs))
1269 fprintf(file, "optstr: %s\n", mnt_fs_get_options(fs));
1270 if (mnt_fs_get_vfs_options(fs))
1271 fprintf(file, "VFS-optstr: %s\n", mnt_fs_get_vfs_options(fs));
1272 if (mnt_fs_get_fs_options(fs))
1273 fprintf(file, "FS-opstr: %s\n", mnt_fs_get_fs_options(fs));
1274 if (mnt_fs_get_user_options(fs))
1275 fprintf(file, "user-optstr: %s\n", mnt_fs_get_user_options(fs));
1276 if (mnt_fs_get_attributes(fs))
1277 fprintf(file, "attributes: %s\n", mnt_fs_get_attributes(fs));
1278
1279 if (mnt_fs_get_root(fs))
1280 fprintf(file, "root: %s\n", mnt_fs_get_root(fs));
1281 if (mnt_fs_get_bindsrc(fs))
1282 fprintf(file, "bindsrc: %s\n", mnt_fs_get_bindsrc(fs));
1283 if (mnt_fs_get_freq(fs))
1284 fprintf(file, "freq: %d\n", mnt_fs_get_freq(fs));
1285 if (mnt_fs_get_passno(fs))
1286 fprintf(file, "pass: %d\n", mnt_fs_get_passno(fs));
1287 if (mnt_fs_get_id(fs))
1288 fprintf(file, "id: %d\n", mnt_fs_get_id(fs));
1289 if (mnt_fs_get_parent_id(fs))
1290 fprintf(file, "parent: %d\n", mnt_fs_get_parent_id(fs));
1291 if (mnt_fs_get_devno(fs))
1292 fprintf(file, "devno: %d:%d\n", major(mnt_fs_get_devno(fs)),
1293 minor(mnt_fs_get_devno(fs)));
1294 return 0;
1295 }
1296
1297 /**
1298 * mnt_free_mntent:
1299 * @mnt: mount entry
1300 *
1301 * Deallocates "mntent.h" mount entry.
1302 */
1303 void mnt_free_mntent(struct mntent *mnt)
1304 {
1305 if (mnt) {
1306 free(mnt->mnt_fsname);
1307 free(mnt->mnt_dir);
1308 free(mnt->mnt_type);
1309 free(mnt->mnt_opts);
1310 free(mnt);
1311 }
1312 }
1313
1314 /**
1315 * mnt_fs_to_mntent:
1316 * @fs: filesystem
1317 * @mnt: mount description (as described in mntent.h)
1318 *
1319 * Copies information from @fs to struct mntent @mnt. If @mnt is already set
1320 * then the struct mntent items are reallocated and updated. See also
1321 * mnt_free_mntent().
1322 *
1323 * Returns: 0 on success and negative number in case of error.
1324 */
1325 int mnt_fs_to_mntent(struct libmnt_fs *fs, struct mntent **mnt)
1326 {
1327 int rc;
1328 struct mntent *m;
1329
1330 if (!fs || !mnt)
1331 return -EINVAL;
1332
1333 m = *mnt;
1334 if (!m) {
1335 m = calloc(1, sizeof(*m));
1336 if (!m)
1337 return -ENOMEM;
1338 }
1339
1340 if ((rc = update_str(&m->mnt_fsname, mnt_fs_get_source(fs))))
1341 goto err;
1342 if ((rc = update_str(&m->mnt_dir, mnt_fs_get_target(fs))))
1343 goto err;
1344 if ((rc = update_str(&m->mnt_type, mnt_fs_get_fstype(fs))))
1345 goto err;
1346
1347 errno = 0;
1348 m->mnt_opts = mnt_fs_strdup_options(fs);
1349 if (!m->mnt_opts && errno) {
1350 rc = -errno;
1351 goto err;
1352 }
1353
1354 m->mnt_freq = mnt_fs_get_freq(fs);
1355 m->mnt_passno = mnt_fs_get_passno(fs);
1356
1357 if (!m->mnt_fsname) {
1358 m->mnt_fsname = strdup("none");
1359 if (!m->mnt_fsname)
1360 goto err;
1361 }
1362 *mnt = m;
1363
1364 return 0;
1365 err:
1366 if (m != *mnt)
1367 mnt_free_mntent(m);
1368 return rc;
1369 }