1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /*
3 * This file is part of libmount from util-linux project.
4 *
5 * Copyright (C) 2008-2018 Karel Zak <kzak@redhat.com>
6 *
7 * libmount is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
11 */
12
13 /**
14 * SECTION: fs
15 * @title: Filesystem
16 * @short_description: represents one entry from fstab, mtab, or mountinfo file
17 *
18 */
19 #include <ctype.h>
20 #include <blkid.h>
21 #include <stddef.h>
22
23 #include "mountP.h"
24 #include "strutils.h"
25
26 /**
27 * mnt_new_fs:
28 *
29 * The initial refcount is 1, and needs to be decremented to
30 * release the resources of the filesystem.
31 *
32 * Returns: newly allocated struct libmnt_fs.
33 */
mnt_new_fs(void)34 struct libmnt_fs *mnt_new_fs(void)
35 {
36 struct libmnt_fs *fs = calloc(1, sizeof(*fs));
37 if (!fs)
38 return NULL;
39
40 fs->refcount = 1;
41 INIT_LIST_HEAD(&fs->ents);
42 DBG(FS, ul_debugobj(fs, "alloc"));
43 return fs;
44 }
45
46 /**
47 * mnt_free_fs:
48 * @fs: fs pointer
49 *
50 * Deallocates the fs. This function does not care about reference count. Don't
51 * use this function directly -- it's better to use mnt_unref_fs().
52 *
53 * The reference counting is supported since util-linux v2.24.
54 */
mnt_free_fs(struct libmnt_fs * fs)55 void mnt_free_fs(struct libmnt_fs *fs)
56 {
57 if (!fs)
58 return;
59
60 DBG(FS, ul_debugobj(fs, "free [refcount=%d]", fs->refcount));
61
62 mnt_reset_fs(fs);
63 free(fs);
64 }
65
66 /**
67 * mnt_reset_fs:
68 * @fs: fs pointer
69 *
70 * Resets (zeroize) @fs.
71 */
mnt_reset_fs(struct libmnt_fs * fs)72 void mnt_reset_fs(struct libmnt_fs *fs)
73 {
74 int ref;
75
76 if (!fs)
77 return;
78
79 ref = fs->refcount;
80
81 list_del(&fs->ents);
82 free(fs->source);
83 free(fs->bindsrc);
84 free(fs->tagname);
85 free(fs->tagval);
86 free(fs->root);
87 free(fs->swaptype);
88 free(fs->target);
89 free(fs->fstype);
90 free(fs->optstr);
91 free(fs->vfs_optstr);
92 free(fs->fs_optstr);
93 free(fs->user_optstr);
94 free(fs->attrs);
95 free(fs->opt_fields);
96 free(fs->comment);
97
98 memset(fs, 0, sizeof(*fs));
99 INIT_LIST_HEAD(&fs->ents);
100 fs->refcount = ref;
101 }
102
103 /**
104 * mnt_ref_fs:
105 * @fs: fs pointer
106 *
107 * Increments reference counter.
108 */
mnt_ref_fs(struct libmnt_fs * fs)109 void mnt_ref_fs(struct libmnt_fs *fs)
110 {
111 if (fs) {
112 fs->refcount++;
113 /*DBG(FS, ul_debugobj(fs, "ref=%d", fs->refcount));*/
114 }
115 }
116
117 /**
118 * mnt_unref_fs:
119 * @fs: fs pointer
120 *
121 * De-increments reference counter, on zero the @fs is automatically
122 * deallocated by mnt_free_fs().
123 */
mnt_unref_fs(struct libmnt_fs * fs)124 void mnt_unref_fs(struct libmnt_fs *fs)
125 {
126 if (fs) {
127 fs->refcount--;
128 /*DBG(FS, ul_debugobj(fs, "unref=%d", fs->refcount));*/
129 if (fs->refcount <= 0)
130 mnt_free_fs(fs);
131 }
132 }
133
update_str(char ** dest,const char * src)134 static inline int update_str(char **dest, const char *src)
135 {
136 size_t sz;
137 char *x;
138
139 assert(dest);
140
141 if (!src) {
142 free(*dest);
143 *dest = NULL;
144 return 0; /* source (old) is empty */
145 }
146
147 sz = strlen(src) + 1;
148 x = realloc(*dest, sz);
149 if (!x)
150 return -ENOMEM;
151 *dest = x;
152 memcpy(*dest, src, sz);
153 return 0;
154 }
155
156 /* This function do NOT overwrite (replace) the string in @new, the string in
157 * the @new has to be NULL otherwise this is no-op */
cpy_str_at_offset(void * new,const void * old,size_t offset)158 static inline int cpy_str_at_offset(void *new, const void *old, size_t offset)
159 {
160 char **o = (char **) ((char *) old + offset);
161 char **n = (char **) ((char *) new + offset);
162
163 if (*n)
164 return 0; /* already set, don't overwrite */
165
166 return update_str(n, *o);
167 }
168
169 /**
170 * mnt_copy_fs:
171 * @dest: destination FS
172 * @src: source FS
173 *
174 * If @dest is NULL, then a new FS is allocated, if any @dest field is already
175 * set, then the field is NOT overwritten.
176 *
177 * This function does not copy userdata (se mnt_fs_set_userdata()). A new copy is
178 * not linked with any existing mnt_tab.
179 *
180 * Returns: @dest or NULL in case of error
181 */
mnt_copy_fs(struct libmnt_fs * dest,const struct libmnt_fs * src)182 struct libmnt_fs *mnt_copy_fs(struct libmnt_fs *dest,
183 const struct libmnt_fs *src)
184 {
185 const struct libmnt_fs *org = dest;
186
187 if (!src)
188 return NULL;
189 if (!dest) {
190 dest = mnt_new_fs();
191 if (!dest)
192 return NULL;
193
194 dest->tab = NULL;
195 }
196
197 dest->id = src->id;
198 dest->parent = src->parent;
199 dest->devno = src->devno;
200 dest->tid = src->tid;
201
202 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, source)))
203 goto err;
204 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, tagname)))
205 goto err;
206 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, tagval)))
207 goto err;
208 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, root)))
209 goto err;
210 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, swaptype)))
211 goto err;
212 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, target)))
213 goto err;
214 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, fstype)))
215 goto err;
216 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, optstr)))
217 goto err;
218 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, vfs_optstr)))
219 goto err;
220 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, fs_optstr)))
221 goto err;
222 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, user_optstr)))
223 goto err;
224 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, attrs)))
225 goto err;
226 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, bindsrc)))
227 goto err;
228
229 dest->freq = src->freq;
230 dest->passno = src->passno;
231 dest->flags = src->flags;
232 dest->size = src->size;
233 dest->usedsize = src->usedsize;
234 dest->priority = src->priority;
235
236 return dest;
237 err:
238 if (!org)
239 mnt_free_fs(dest);
240 return NULL;
241 }
242
243 /*
244 * This function copies all @fs description except information that does not
245 * belong to /etc/mtab (e.g. VFS and userspace mount options with MNT_NOMTAB
246 * mask).
247 *
248 * Returns: copy of @fs.
249 */
mnt_copy_mtab_fs(const struct libmnt_fs * fs)250 struct libmnt_fs *mnt_copy_mtab_fs(const struct libmnt_fs *fs)
251 {
252 struct libmnt_fs *n = mnt_new_fs();
253
254 assert(fs);
255 if (!n)
256 return NULL;
257
258 if (strdup_between_structs(n, fs, source))
259 goto err;
260 if (strdup_between_structs(n, fs, target))
261 goto err;
262 if (strdup_between_structs(n, fs, fstype))
263 goto err;
264
265 if (fs->vfs_optstr) {
266 char *p = NULL;
267 mnt_optstr_get_options(fs->vfs_optstr, &p,
268 mnt_get_builtin_optmap(MNT_LINUX_MAP),
269 MNT_NOMTAB);
270 n->vfs_optstr = p;
271 }
272
273 if (fs->user_optstr) {
274 char *p = NULL;
275 mnt_optstr_get_options(fs->user_optstr, &p,
276 mnt_get_builtin_optmap(MNT_USERSPACE_MAP),
277 MNT_NOMTAB);
278 n->user_optstr = p;
279 }
280
281 if (strdup_between_structs(n, fs, fs_optstr))
282 goto err;
283
284 /* we cannot copy original optstr, the new optstr has to be without
285 * non-mtab options -- so, let's generate a new string */
286 n->optstr = mnt_fs_strdup_options(n);
287
288 n->freq = fs->freq;
289 n->passno = fs->passno;
290 n->flags = fs->flags;
291
292 return n;
293 err:
294 mnt_free_fs(n);
295 return NULL;
296
297 }
298
299 /**
300 * mnt_fs_get_userdata:
301 * @fs: struct libmnt_file instance
302 *
303 * Returns: private data set by mnt_fs_set_userdata() or NULL.
304 */
mnt_fs_get_userdata(struct libmnt_fs * fs)305 void *mnt_fs_get_userdata(struct libmnt_fs *fs)
306 {
307 if (!fs)
308 return NULL;
309 return fs->userdata;
310 }
311
312 /**
313 * mnt_fs_set_userdata:
314 * @fs: struct libmnt_file instance
315 * @data: user data
316 *
317 * The "userdata" are library independent data.
318 *
319 * Returns: 0 or negative number in case of error (if @fs is NULL).
320 */
mnt_fs_set_userdata(struct libmnt_fs * fs,void * data)321 int mnt_fs_set_userdata(struct libmnt_fs *fs, void *data)
322 {
323 if (!fs)
324 return -EINVAL;
325 fs->userdata = data;
326 return 0;
327 }
328
329 /**
330 * mnt_fs_get_srcpath:
331 * @fs: struct libmnt_file (fstab/mtab/mountinfo) fs
332 *
333 * The mount "source path" is:
334 * - a directory for 'bind' mounts (in fstab or mtab only)
335 * - a device name for standard mounts
336 *
337 * See also mnt_fs_get_tag() and mnt_fs_get_source().
338 *
339 * Returns: mount source path or NULL in case of error or when the path
340 * is not defined.
341 */
mnt_fs_get_srcpath(struct libmnt_fs * fs)342 const char *mnt_fs_get_srcpath(struct libmnt_fs *fs)
343 {
344 if (!fs)
345 return NULL;
346
347 /* fstab-like fs */
348 if (fs->tagname)
349 return NULL; /* the source contains a "NAME=value" */
350 return fs->source;
351 }
352
353 /**
354 * mnt_fs_get_source:
355 * @fs: struct libmnt_file (fstab/mtab/mountinfo) fs
356 *
357 * Returns: mount source. Note that the source could be unparsed TAG
358 * (LABEL/UUID). See also mnt_fs_get_srcpath() and mnt_fs_get_tag().
359 */
mnt_fs_get_source(struct libmnt_fs * fs)360 const char *mnt_fs_get_source(struct libmnt_fs *fs)
361 {
362 return fs ? fs->source : NULL;
363 }
364
365 /*
366 * Used by the parser ONLY (@source has to be freed on error)
367 */
__mnt_fs_set_source_ptr(struct libmnt_fs * fs,char * source)368 int __mnt_fs_set_source_ptr(struct libmnt_fs *fs, char *source)
369 {
370 char *t = NULL, *v = NULL;
371
372 assert(fs);
373
374 if (source && blkid_parse_tag_string(source, &t, &v) == 0 &&
375 !mnt_valid_tagname(t)) {
376 /* parsable but unknown tag -- ignore */
377 free(t);
378 free(v);
379 t = v = NULL;
380 }
381
382 if (fs->source != source)
383 free(fs->source);
384
385 free(fs->tagname);
386 free(fs->tagval);
387
388 fs->source = source;
389 fs->tagname = t;
390 fs->tagval = v;
391 return 0;
392 }
393
394 /**
395 * mnt_fs_set_source:
396 * @fs: fstab/mtab/mountinfo entry
397 * @source: new source
398 *
399 * This function creates a private copy (strdup()) of @source.
400 *
401 * Returns: 0 on success or negative number in case of error.
402 */
mnt_fs_set_source(struct libmnt_fs * fs,const char * source)403 int mnt_fs_set_source(struct libmnt_fs *fs, const char *source)
404 {
405 char *p = NULL;
406 int rc;
407
408 if (!fs)
409 return -EINVAL;
410
411 if (source) {
412 p = strdup(source);
413 if (!p)
414 return -ENOMEM;
415 }
416
417 rc = __mnt_fs_set_source_ptr(fs, p);
418 if (rc)
419 free(p);
420 return rc;
421 }
422
423 /**
424 * mnt_fs_streq_srcpath:
425 * @fs: fs
426 * @path: source path
427 *
428 * Compares @fs source path with @path. The redundant slashes are ignored.
429 * This function compares strings and does not canonicalize the paths.
430 * See also more heavy and generic mnt_fs_match_source().
431 *
432 * Returns: 1 if @fs source path equal to @path, otherwise 0.
433 */
mnt_fs_streq_srcpath(struct libmnt_fs * fs,const char * path)434 int mnt_fs_streq_srcpath(struct libmnt_fs *fs, const char *path)
435 {
436 const char *p;
437
438 if (!fs)
439 return 0;
440
441 p = mnt_fs_get_srcpath(fs);
442
443 if (!mnt_fs_is_pseudofs(fs))
444 return streq_paths(p, path);
445
446 if (!p && !path)
447 return 1;
448
449 return p && path && strcmp(p, path) == 0;
450 }
451
452 /**
453 * mnt_fs_get_table:
454 * @fs: table entry
455 * @tb: table that contains @fs
456 *
457 * Returns: 0 or negative number on error (if @fs or @tb is NULL).
458 *
459 * Since: 2.34
460 */
mnt_fs_get_table(struct libmnt_fs * fs,struct libmnt_table ** tb)461 int mnt_fs_get_table(struct libmnt_fs *fs, struct libmnt_table **tb)
462 {
463 if (!fs || !tb)
464 return -EINVAL;
465
466 *tb = fs->tab;
467 return 0;
468 }
469
470 /**
471 * mnt_fs_streq_target:
472 * @fs: fs
473 * @path: mount point
474 *
475 * Compares @fs target path with @path. The redundant slashes are ignored.
476 * This function compares strings and does not canonicalize the paths.
477 * See also more generic mnt_fs_match_target().
478 *
479 * Returns: 1 if @fs target path equal to @path, otherwise 0.
480 */
mnt_fs_streq_target(struct libmnt_fs * fs,const char * path)481 int mnt_fs_streq_target(struct libmnt_fs *fs, const char *path)
482 {
483 return fs && streq_paths(mnt_fs_get_target(fs), path);
484 }
485
486 /**
487 * mnt_fs_get_tag:
488 * @fs: fs
489 * @name: returns pointer to NAME string
490 * @value: returns pointer to VALUE string
491 *
492 * "TAG" is NAME=VALUE (e.g. LABEL=foo)
493 *
494 * The TAG is the first column in the fstab file. The TAG or "srcpath" always has
495 * to be set for all entries.
496 *
497 * See also mnt_fs_get_source().
498 *
499 * <informalexample>
500 * <programlisting>
501 * char *src;
502 * struct libmnt_fs *fs = mnt_table_find_target(tb, "/home", MNT_ITER_FORWARD);
503 *
504 * if (!fs)
505 * goto err;
506 *
507 * src = mnt_fs_get_srcpath(fs);
508 * if (!src) {
509 * char *tag, *val;
510 * if (mnt_fs_get_tag(fs, &tag, &val) == 0)
511 * printf("%s: %s\n", tag, val); // LABEL or UUID
512 * } else
513 * printf("device: %s\n", src); // device or bind path
514 * </programlisting>
515 * </informalexample>
516 *
517 * Returns: 0 on success or negative number in case a TAG is not defined.
518 */
mnt_fs_get_tag(struct libmnt_fs * fs,const char ** name,const char ** value)519 int mnt_fs_get_tag(struct libmnt_fs *fs, const char **name, const char **value)
520 {
521 if (fs == NULL || !fs->tagname)
522 return -EINVAL;
523 if (name)
524 *name = fs->tagname;
525 if (value)
526 *value = fs->tagval;
527 return 0;
528 }
529
530 /**
531 * mnt_fs_get_target:
532 * @fs: fstab/mtab/mountinfo entry pointer
533 *
534 * Returns: pointer to mountpoint path or NULL
535 */
mnt_fs_get_target(struct libmnt_fs * fs)536 const char *mnt_fs_get_target(struct libmnt_fs *fs)
537 {
538 return fs ? fs->target : NULL;
539 }
540
541 /**
542 * mnt_fs_set_target:
543 * @fs: fstab/mtab/mountinfo entry
544 * @tgt: mountpoint
545 *
546 * This function creates a private copy (strdup()) of @tgt.
547 *
548 * Returns: 0 on success or negative number in case of error.
549 */
mnt_fs_set_target(struct libmnt_fs * fs,const char * tgt)550 int mnt_fs_set_target(struct libmnt_fs *fs, const char *tgt)
551 {
552 return strdup_to_struct_member(fs, target, tgt);
553 }
554
mnt_fs_get_flags(struct libmnt_fs * fs)555 static int mnt_fs_get_flags(struct libmnt_fs *fs)
556 {
557 return fs ? fs->flags : 0;
558 }
559
560 /**
561 * mnt_fs_get_propagation:
562 * @fs: mountinfo entry
563 * @flags: returns propagation MS_* flags as present in the mountinfo file
564 *
565 * Note that this function sets @flags to zero if no propagation flags are found
566 * in the mountinfo file. The kernel default is MS_PRIVATE, this flag is not stored
567 * in the mountinfo file.
568 *
569 * Returns: 0 on success or negative number in case of error.
570 */
mnt_fs_get_propagation(struct libmnt_fs * fs,unsigned long * flags)571 int mnt_fs_get_propagation(struct libmnt_fs *fs, unsigned long *flags)
572 {
573 if (!fs || !flags)
574 return -EINVAL;
575
576 *flags = 0;
577
578 if (!fs->opt_fields)
579 return 0;
580
581 /*
582 * The optional fields format is incompatible with mount options
583 * ... we have to parse the field here.
584 */
585 *flags |= strstr(fs->opt_fields, "shared:") ? MS_SHARED : MS_PRIVATE;
586
587 if (strstr(fs->opt_fields, "master:"))
588 *flags |= MS_SLAVE;
589 if (strstr(fs->opt_fields, "unbindable"))
590 *flags |= MS_UNBINDABLE;
591
592 return 0;
593 }
594
595 /**
596 * mnt_fs_is_kernel:
597 * @fs: filesystem
598 *
599 * Returns: 1 if the filesystem description is read from kernel e.g. /proc/mounts.
600 */
mnt_fs_is_kernel(struct libmnt_fs * fs)601 int mnt_fs_is_kernel(struct libmnt_fs *fs)
602 {
603 return mnt_fs_get_flags(fs) & MNT_FS_KERNEL;
604 }
605
606 /**
607 * mnt_fs_is_swaparea:
608 * @fs: filesystem
609 *
610 * Returns: 1 if the filesystem uses "swap" as a type
611 */
mnt_fs_is_swaparea(struct libmnt_fs * fs)612 int mnt_fs_is_swaparea(struct libmnt_fs *fs)
613 {
614 return mnt_fs_get_flags(fs) & MNT_FS_SWAP;
615 }
616
617 /**
618 * mnt_fs_is_pseudofs:
619 * @fs: filesystem
620 *
621 * Returns: 1 if the filesystem is a pseudo fs type (proc, cgroups)
622 */
mnt_fs_is_pseudofs(struct libmnt_fs * fs)623 int mnt_fs_is_pseudofs(struct libmnt_fs *fs)
624 {
625 return mnt_fs_get_flags(fs) & MNT_FS_PSEUDO;
626 }
627
628 /**
629 * mnt_fs_is_netfs:
630 * @fs: filesystem
631 *
632 * Returns: 1 if the filesystem is a network filesystem
633 */
mnt_fs_is_netfs(struct libmnt_fs * fs)634 int mnt_fs_is_netfs(struct libmnt_fs *fs)
635 {
636 return mnt_fs_get_flags(fs) & MNT_FS_NET;
637 }
638
639 /**
640 * mnt_fs_get_fstype:
641 * @fs: fstab/mtab/mountinfo entry pointer
642 *
643 * Returns: pointer to filesystem type.
644 */
mnt_fs_get_fstype(struct libmnt_fs * fs)645 const char *mnt_fs_get_fstype(struct libmnt_fs *fs)
646 {
647 return fs ? fs->fstype : NULL;
648 }
649
650 /* Used by the struct libmnt_file parser only */
__mnt_fs_set_fstype_ptr(struct libmnt_fs * fs,char * fstype)651 int __mnt_fs_set_fstype_ptr(struct libmnt_fs *fs, char *fstype)
652 {
653 assert(fs);
654
655 if (fstype != fs->fstype)
656 free(fs->fstype);
657
658 fs->fstype = fstype;
659 fs->flags &= ~MNT_FS_PSEUDO;
660 fs->flags &= ~MNT_FS_NET;
661 fs->flags &= ~MNT_FS_SWAP;
662
663 /* save info about pseudo filesystems */
664 if (fs->fstype) {
665 if (mnt_fstype_is_pseudofs(fs->fstype))
666 fs->flags |= MNT_FS_PSEUDO;
667 else if (mnt_fstype_is_netfs(fs->fstype))
668 fs->flags |= MNT_FS_NET;
669 else if (!strcmp(fs->fstype, "swap"))
670 fs->flags |= MNT_FS_SWAP;
671 }
672 return 0;
673 }
674
675 /**
676 * mnt_fs_set_fstype:
677 * @fs: fstab/mtab/mountinfo entry
678 * @fstype: filesystem type
679 *
680 * This function creates a private copy (strdup()) of @fstype.
681 *
682 * Returns: 0 on success or negative number in case of error.
683 */
mnt_fs_set_fstype(struct libmnt_fs * fs,const char * fstype)684 int mnt_fs_set_fstype(struct libmnt_fs *fs, const char *fstype)
685 {
686 char *p = NULL;
687
688 if (!fs)
689 return -EINVAL;
690 if (fstype) {
691 p = strdup(fstype);
692 if (!p)
693 return -ENOMEM;
694 }
695 return __mnt_fs_set_fstype_ptr(fs, p);
696 }
697
698 /*
699 * Merges @vfs and @fs options strings into a new string.
700 * This function cares about 'ro/rw' options. The 'ro' is
701 * always used if @vfs or @fs is read-only.
702 * For example:
703 *
704 * mnt_merge_optstr("rw,noexec", "ro,journal=update")
705 *
706 * returns: "ro,noexec,journal=update"
707 *
708 * mnt_merge_optstr("rw,noexec", "rw,journal=update")
709 *
710 * returns: "rw,noexec,journal=update"
711 */
merge_optstr(const char * vfs,const char * fs)712 static char *merge_optstr(const char *vfs, const char *fs)
713 {
714 char *res, *p;
715 size_t sz;
716 int ro = 0, rw = 0;
717
718 if (!vfs && !fs)
719 return NULL;
720 if (!vfs || !fs)
721 return strdup(fs ? fs : vfs);
722 if (!strcmp(vfs, fs))
723 return strdup(vfs); /* e.g. "aaa" and "aaa" */
724
725 /* leave space for the leading "r[ow],", "," and the trailing zero */
726 sz = strlen(vfs) + strlen(fs) + 5;
727 res = malloc(sz);
728 if (!res)
729 return NULL;
730 p = res + 3; /* make a room for rw/ro flag */
731
732 snprintf(p, sz - 3, "%s,%s", vfs, fs);
733
734 /* remove 'rw' flags */
735 rw += !mnt_optstr_remove_option(&p, "rw"); /* from vfs */
736 rw += !mnt_optstr_remove_option(&p, "rw"); /* from fs */
737
738 /* remove 'ro' flags if necessary */
739 if (rw != 2) {
740 ro += !mnt_optstr_remove_option(&p, "ro");
741 if (ro + rw < 2)
742 ro += !mnt_optstr_remove_option(&p, "ro");
743 }
744
745 if (!strlen(p))
746 memcpy(res, ro ? "ro" : "rw", 3);
747 else
748 memcpy(res, ro ? "ro," : "rw,", 3);
749 return res;
750 }
751
752 /**
753 * mnt_fs_strdup_options:
754 * @fs: fstab/mtab/mountinfo entry pointer
755 *
756 * Merges all mount options (VFS, FS and userspace) to one options string
757 * and returns the result. This function does not modify @fs.
758 *
759 * Returns: pointer to string (can be freed by free(3)) or NULL in case of error.
760 */
mnt_fs_strdup_options(struct libmnt_fs * fs)761 char *mnt_fs_strdup_options(struct libmnt_fs *fs)
762 {
763 char *res;
764
765 if (!fs)
766 return NULL;
767
768 errno = 0;
769 if (fs->optstr)
770 return strdup(fs->optstr);
771
772 res = merge_optstr(fs->vfs_optstr, fs->fs_optstr);
773 if (!res && errno)
774 return NULL;
775 if (fs->user_optstr &&
776 mnt_optstr_append_option(&res, fs->user_optstr, NULL)) {
777 free(res);
778 res = NULL;
779 }
780 return res;
781 }
782
783 /**
784 * mnt_fs_get_options:
785 * @fs: fstab/mtab/mountinfo entry pointer
786 *
787 * Returns: pointer to string or NULL in case of error.
788 */
mnt_fs_get_options(struct libmnt_fs * fs)789 const char *mnt_fs_get_options(struct libmnt_fs *fs)
790 {
791 return fs ? fs->optstr : NULL;
792 }
793
794 /**
795 * mnt_fs_get_optional_fields
796 * @fs: mountinfo entry pointer
797 *
798 * Returns: pointer to string with mountinfo optional fields
799 * or NULL in case of error.
800 */
mnt_fs_get_optional_fields(struct libmnt_fs * fs)801 const char *mnt_fs_get_optional_fields(struct libmnt_fs *fs)
802 {
803 return fs ? fs->opt_fields : NULL;
804 }
805
806 /**
807 * mnt_fs_set_options:
808 * @fs: fstab/mtab/mountinfo entry pointer
809 * @optstr: options string
810 *
811 * Splits @optstr to VFS, FS and userspace mount options and updates relevant
812 * parts of @fs.
813 *
814 * Returns: 0 on success, or negative number in case of error.
815 */
mnt_fs_set_options(struct libmnt_fs * fs,const char * optstr)816 int mnt_fs_set_options(struct libmnt_fs *fs, const char *optstr)
817 {
818 char *v = NULL, *f = NULL, *u = NULL, *n = NULL;
819
820 if (!fs)
821 return -EINVAL;
822 if (optstr) {
823 int rc = mnt_split_optstr(optstr, &u, &v, &f, 0, 0);
824 if (rc)
825 return rc;
826 n = strdup(optstr);
827 if (!n) {
828 free(u);
829 free(v);
830 free(f);
831 return -ENOMEM;
832 }
833 }
834
835 free(fs->fs_optstr);
836 free(fs->vfs_optstr);
837 free(fs->user_optstr);
838 free(fs->optstr);
839
840 fs->fs_optstr = f;
841 fs->vfs_optstr = v;
842 fs->user_optstr = u;
843 fs->optstr = n;
844
845 return 0;
846 }
847
848 /**
849 * mnt_fs_append_options:
850 * @fs: fstab/mtab/mountinfo entry
851 * @optstr: mount options
852 *
853 * Parses (splits) @optstr and appends results to VFS, FS and userspace lists
854 * of options.
855 *
856 * If @optstr is NULL, then @fs is not modified and 0 is returned.
857 *
858 * Returns: 0 on success or negative number in case of error.
859 */
mnt_fs_append_options(struct libmnt_fs * fs,const char * optstr)860 int mnt_fs_append_options(struct libmnt_fs *fs, const char *optstr)
861 {
862 char *v = NULL, *f = NULL, *u = NULL;
863 int rc;
864
865 if (!fs)
866 return -EINVAL;
867 if (!optstr)
868 return 0;
869
870 rc = mnt_split_optstr(optstr, &u, &v, &f, 0, 0);
871 if (rc)
872 return rc;
873
874 if (!rc && v)
875 rc = mnt_optstr_append_option(&fs->vfs_optstr, v, NULL);
876 if (!rc && f)
877 rc = mnt_optstr_append_option(&fs->fs_optstr, f, NULL);
878 if (!rc && u)
879 rc = mnt_optstr_append_option(&fs->user_optstr, u, NULL);
880 if (!rc)
881 rc = mnt_optstr_append_option(&fs->optstr, optstr, NULL);
882
883 free(v);
884 free(f);
885 free(u);
886
887 return rc;
888 }
889
890 /**
891 * mnt_fs_prepend_options:
892 * @fs: fstab/mtab/mountinfo entry
893 * @optstr: mount options
894 *
895 * Parses (splits) @optstr and prepends the results to VFS, FS and userspace lists
896 * of options.
897 *
898 * If @optstr is NULL, then @fs is not modified and 0 is returned.
899 *
900 * Returns: 0 on success or negative number in case of error.
901 */
mnt_fs_prepend_options(struct libmnt_fs * fs,const char * optstr)902 int mnt_fs_prepend_options(struct libmnt_fs *fs, const char *optstr)
903 {
904 char *v = NULL, *f = NULL, *u = NULL;
905 int rc;
906
907 if (!fs)
908 return -EINVAL;
909 if (!optstr)
910 return 0;
911
912 rc = mnt_split_optstr(optstr, &u, &v, &f, 0, 0);
913 if (rc)
914 return rc;
915
916 if (!rc && v)
917 rc = mnt_optstr_prepend_option(&fs->vfs_optstr, v, NULL);
918 if (!rc && f)
919 rc = mnt_optstr_prepend_option(&fs->fs_optstr, f, NULL);
920 if (!rc && u)
921 rc = mnt_optstr_prepend_option(&fs->user_optstr, u, NULL);
922 if (!rc)
923 rc = mnt_optstr_prepend_option(&fs->optstr, optstr, NULL);
924
925 free(v);
926 free(f);
927 free(u);
928
929 return rc;
930 }
931
932 /*
933 * mnt_fs_get_fs_options:
934 * @fs: fstab/mtab/mountinfo entry pointer
935 *
936 * Returns: pointer to superblock (fs-depend) mount option string or NULL.
937 */
mnt_fs_get_fs_options(struct libmnt_fs * fs)938 const char *mnt_fs_get_fs_options(struct libmnt_fs *fs)
939 {
940 return fs ? fs->fs_optstr : NULL;
941 }
942
943 /**
944 * mnt_fs_get_vfs_options:
945 * @fs: fstab/mtab entry pointer
946 *
947 * Returns: pointer to fs-independent (VFS) mount option string or NULL.
948 */
mnt_fs_get_vfs_options(struct libmnt_fs * fs)949 const char *mnt_fs_get_vfs_options(struct libmnt_fs *fs)
950 {
951 return fs ? fs->vfs_optstr : NULL;
952 }
953
954 /**
955 * mnt_fs_get_user_options:
956 * @fs: fstab/mtab entry pointer
957 *
958 * Returns: pointer to userspace mount option string or NULL.
959 */
mnt_fs_get_user_options(struct libmnt_fs * fs)960 const char *mnt_fs_get_user_options(struct libmnt_fs *fs)
961 {
962 return fs ? fs->user_optstr : NULL;
963 }
964
965 /**
966 * mnt_fs_get_attributes:
967 * @fs: fstab/mtab entry pointer
968 *
969 * Returns: pointer to attributes string or NULL.
970 */
mnt_fs_get_attributes(struct libmnt_fs * fs)971 const char *mnt_fs_get_attributes(struct libmnt_fs *fs)
972 {
973 return fs ? fs->attrs : NULL;
974 }
975
976 /**
977 * mnt_fs_set_attributes:
978 * @fs: fstab/mtab/mountinfo entry
979 * @optstr: options string
980 *
981 * Sets mount attributes. The attributes are mount(2) and mount(8) independent
982 * options, these options are not sent to the kernel and are not interpreted by
983 * libmount. The attributes are stored in /run/mount/utab only.
984 *
985 * The attributes are managed by libmount in userspace only. It's possible
986 * that information stored in userspace will not be available for libmount
987 * after CLONE_FS unshare. Be careful, and don't use attributes if possible.
988 *
989 * Returns: 0 on success or negative number in case of error.
990 */
mnt_fs_set_attributes(struct libmnt_fs * fs,const char * optstr)991 int mnt_fs_set_attributes(struct libmnt_fs *fs, const char *optstr)
992 {
993 return strdup_to_struct_member(fs, attrs, optstr);
994 }
995
996 /**
997 * mnt_fs_append_attributes
998 * @fs: fstab/mtab/mountinfo entry
999 * @optstr: options string
1000 *
1001 * Appends mount attributes. (See mnt_fs_set_attributes()).
1002 *
1003 * Returns: 0 on success or negative number in case of error.
1004 */
mnt_fs_append_attributes(struct libmnt_fs * fs,const char * optstr)1005 int mnt_fs_append_attributes(struct libmnt_fs *fs, const char *optstr)
1006 {
1007 if (!fs)
1008 return -EINVAL;
1009 if (!optstr)
1010 return 0;
1011 return mnt_optstr_append_option(&fs->attrs, optstr, NULL);
1012 }
1013
1014 /**
1015 * mnt_fs_prepend_attributes
1016 * @fs: fstab/mtab/mountinfo entry
1017 * @optstr: options string
1018 *
1019 * Prepends mount attributes. (See mnt_fs_set_attributes()).
1020 *
1021 * Returns: 0 on success or negative number in case of error.
1022 */
mnt_fs_prepend_attributes(struct libmnt_fs * fs,const char * optstr)1023 int mnt_fs_prepend_attributes(struct libmnt_fs *fs, const char *optstr)
1024 {
1025 if (!fs)
1026 return -EINVAL;
1027 if (!optstr)
1028 return 0;
1029 return mnt_optstr_prepend_option(&fs->attrs, optstr, NULL);
1030 }
1031
1032
1033 /**
1034 * mnt_fs_get_freq:
1035 * @fs: fstab/mtab/mountinfo entry pointer
1036 *
1037 * Returns: dump frequency in days.
1038 */
mnt_fs_get_freq(struct libmnt_fs * fs)1039 int mnt_fs_get_freq(struct libmnt_fs *fs)
1040 {
1041 return fs ? fs->freq : 0;
1042 }
1043
1044 /**
1045 * mnt_fs_set_freq:
1046 * @fs: fstab/mtab entry pointer
1047 * @freq: dump frequency in days
1048 *
1049 * Returns: 0 on success or negative number in case of error.
1050 */
mnt_fs_set_freq(struct libmnt_fs * fs,int freq)1051 int mnt_fs_set_freq(struct libmnt_fs *fs, int freq)
1052 {
1053 if (!fs)
1054 return -EINVAL;
1055 fs->freq = freq;
1056 return 0;
1057 }
1058
1059 /**
1060 * mnt_fs_get_passno:
1061 * @fs: fstab/mtab entry pointer
1062 *
1063 * Returns: "pass number on parallel fsck".
1064 */
mnt_fs_get_passno(struct libmnt_fs * fs)1065 int mnt_fs_get_passno(struct libmnt_fs *fs)
1066 {
1067 return fs ? fs->passno: 0;
1068 }
1069
1070 /**
1071 * mnt_fs_set_passno:
1072 * @fs: fstab/mtab entry pointer
1073 * @passno: pass number
1074 *
1075 * Returns: 0 on success or negative number in case of error.
1076 */
mnt_fs_set_passno(struct libmnt_fs * fs,int passno)1077 int mnt_fs_set_passno(struct libmnt_fs *fs, int passno)
1078 {
1079 if (!fs)
1080 return -EINVAL;
1081 fs->passno = passno;
1082 return 0;
1083 }
1084
1085 /**
1086 * mnt_fs_get_root:
1087 * @fs: /proc/self/mountinfo entry
1088 *
1089 * Returns: root of the mount within the filesystem or NULL
1090 */
mnt_fs_get_root(struct libmnt_fs * fs)1091 const char *mnt_fs_get_root(struct libmnt_fs *fs)
1092 {
1093 return fs ? fs->root : NULL;
1094 }
1095
1096 /**
1097 * mnt_fs_set_root:
1098 * @fs: mountinfo entry
1099 * @path: root path
1100 *
1101 * Returns: 0 on success or negative number in case of error.
1102 */
mnt_fs_set_root(struct libmnt_fs * fs,const char * path)1103 int mnt_fs_set_root(struct libmnt_fs *fs, const char *path)
1104 {
1105 return strdup_to_struct_member(fs, root, path);
1106 }
1107
1108 /**
1109 * mnt_fs_get_swaptype:
1110 * @fs: /proc/swaps entry
1111 *
1112 * Returns: swap type or NULL
1113 */
mnt_fs_get_swaptype(struct libmnt_fs * fs)1114 const char *mnt_fs_get_swaptype(struct libmnt_fs *fs)
1115 {
1116 return fs ? fs->swaptype : NULL;
1117 }
1118
1119 /**
1120 * mnt_fs_get_size:
1121 * @fs: /proc/swaps entry
1122 *
1123 * Returns: size
1124 */
mnt_fs_get_size(struct libmnt_fs * fs)1125 off_t mnt_fs_get_size(struct libmnt_fs *fs)
1126 {
1127 return fs ? fs->size : 0;
1128 }
1129
1130 /**
1131 * mnt_fs_get_usedsize:
1132 * @fs: /proc/swaps entry
1133 *
1134 * Returns: used size
1135 */
mnt_fs_get_usedsize(struct libmnt_fs * fs)1136 off_t mnt_fs_get_usedsize(struct libmnt_fs *fs)
1137 {
1138 return fs ? fs->usedsize : 0;
1139 }
1140
1141 /**
1142 * mnt_fs_get_priority:
1143 * @fs: /proc/swaps entry
1144 *
1145 * Returns: priority
1146 */
mnt_fs_get_priority(struct libmnt_fs * fs)1147 int mnt_fs_get_priority(struct libmnt_fs *fs)
1148 {
1149 return fs ? fs->priority : 0;
1150 }
1151
1152 /**
1153 * mnt_fs_set_priority:
1154 * @fs: /proc/swaps entry
1155 * @prio: priority
1156 *
1157 * Since: 2.28
1158 *
1159 * Returns: 0 or -1 in case of error
1160 */
mnt_fs_set_priority(struct libmnt_fs * fs,int prio)1161 int mnt_fs_set_priority(struct libmnt_fs *fs, int prio)
1162 {
1163 if (!fs)
1164 return -EINVAL;
1165 fs->priority = prio;
1166 return 0;
1167 }
1168
1169 /**
1170 * mnt_fs_get_bindsrc:
1171 * @fs: /run/mount/utab entry
1172 *
1173 * Returns: full path that was used for mount(2) on MS_BIND
1174 */
mnt_fs_get_bindsrc(struct libmnt_fs * fs)1175 const char *mnt_fs_get_bindsrc(struct libmnt_fs *fs)
1176 {
1177 return fs ? fs->bindsrc : NULL;
1178 }
1179
1180 /**
1181 * mnt_fs_set_bindsrc:
1182 * @fs: filesystem
1183 * @src: path
1184 *
1185 * Returns: 0 on success or negative number in case of error.
1186 */
mnt_fs_set_bindsrc(struct libmnt_fs * fs,const char * src)1187 int mnt_fs_set_bindsrc(struct libmnt_fs *fs, const char *src)
1188 {
1189 return strdup_to_struct_member(fs, bindsrc, src);
1190 }
1191
1192 /**
1193 * mnt_fs_get_id:
1194 * @fs: /proc/self/mountinfo entry
1195 *
1196 * Returns: mount ID (unique identifier of the mount) or negative number in case of error.
1197 */
mnt_fs_get_id(struct libmnt_fs * fs)1198 int mnt_fs_get_id(struct libmnt_fs *fs)
1199 {
1200 return fs ? fs->id : -EINVAL;
1201 }
1202
1203 /**
1204 * mnt_fs_get_parent_id:
1205 * @fs: /proc/self/mountinfo entry
1206 *
1207 * Returns: parent mount ID or negative number in case of error.
1208 */
mnt_fs_get_parent_id(struct libmnt_fs * fs)1209 int mnt_fs_get_parent_id(struct libmnt_fs *fs)
1210 {
1211 return fs ? fs->parent : -EINVAL;
1212 }
1213
1214 /**
1215 * mnt_fs_get_devno:
1216 * @fs: /proc/self/mountinfo entry
1217 *
1218 * Returns: value of st_dev for files on filesystem or 0 in case of error.
1219 */
mnt_fs_get_devno(struct libmnt_fs * fs)1220 dev_t mnt_fs_get_devno(struct libmnt_fs *fs)
1221 {
1222 return fs ? fs->devno : 0;
1223 }
1224
1225 /**
1226 * mnt_fs_get_tid:
1227 * @fs: /proc/tid/mountinfo entry
1228 *
1229 * Returns: TID (task ID) for filesystems read from the mountinfo file
1230 */
mnt_fs_get_tid(struct libmnt_fs * fs)1231 pid_t mnt_fs_get_tid(struct libmnt_fs *fs)
1232 {
1233 return fs ? fs->tid : 0;
1234 }
1235
1236 /**
1237 * mnt_fs_get_option:
1238 * @fs: fstab/mtab/mountinfo entry pointer
1239 * @name: option name
1240 * @value: returns pointer to the beginning of the value (e.g. name=VALUE) or NULL
1241 * @valsz: returns size of options value or 0
1242 *
1243 * Returns: 0 on success, 1 when @name not found or negative number in case of error.
1244 */
mnt_fs_get_option(struct libmnt_fs * fs,const char * name,char ** value,size_t * valsz)1245 int mnt_fs_get_option(struct libmnt_fs *fs, const char *name,
1246 char **value, size_t *valsz)
1247 {
1248 char rc = 1;
1249
1250 if (!fs)
1251 return -EINVAL;
1252 if (fs->fs_optstr)
1253 rc = mnt_optstr_get_option(fs->fs_optstr, name, value, valsz);
1254 if (rc == 1 && fs->vfs_optstr)
1255 rc = mnt_optstr_get_option(fs->vfs_optstr, name, value, valsz);
1256 if (rc == 1 && fs->user_optstr)
1257 rc = mnt_optstr_get_option(fs->user_optstr, name, value, valsz);
1258 return rc;
1259 }
1260
1261 /**
1262 * mnt_fs_get_attribute:
1263 * @fs: fstab/mtab/mountinfo entry pointer
1264 * @name: option name
1265 * @value: returns pointer to the beginning of the value (e.g. name=VALUE) or NULL
1266 * @valsz: returns size of options value or 0
1267 *
1268 * Returns: 0 on success, 1 when @name not found or negative number in case of error.
1269 */
mnt_fs_get_attribute(struct libmnt_fs * fs,const char * name,char ** value,size_t * valsz)1270 int mnt_fs_get_attribute(struct libmnt_fs *fs, const char *name,
1271 char **value, size_t *valsz)
1272 {
1273 char rc = 1;
1274
1275 if (!fs)
1276 return -EINVAL;
1277 if (fs->attrs)
1278 rc = mnt_optstr_get_option(fs->attrs, name, value, valsz);
1279 return rc;
1280 }
1281
1282 /**
1283 * mnt_fs_get_comment:
1284 * @fs: fstab/mtab/mountinfo entry pointer
1285 *
1286 * Returns: 0 on success, 1 when not found the @name or negative number in case of error.
1287 */
mnt_fs_get_comment(struct libmnt_fs * fs)1288 const char *mnt_fs_get_comment(struct libmnt_fs *fs)
1289 {
1290 if (!fs)
1291 return NULL;
1292 return fs->comment;
1293 }
1294
1295 /**
1296 * mnt_fs_set_comment:
1297 * @fs: fstab entry pointer
1298 * @comm: comment string
1299 *
1300 * Note that the comment has to be terminated by '\n' (new line), otherwise
1301 * the whole filesystem entry will be written as a comment to the tabfile (e.g.
1302 * fstab).
1303 *
1304 * Returns: 0 on success or <0 in case of error.
1305 */
mnt_fs_set_comment(struct libmnt_fs * fs,const char * comm)1306 int mnt_fs_set_comment(struct libmnt_fs *fs, const char *comm)
1307 {
1308 return strdup_to_struct_member(fs, comment, comm);
1309 }
1310
1311 /**
1312 * mnt_fs_append_comment:
1313 * @fs: fstab entry pointer
1314 * @comm: comment string
1315 *
1316 * See also mnt_fs_set_comment().
1317 *
1318 * Returns: 0 on success or <0 in case of error.
1319 */
mnt_fs_append_comment(struct libmnt_fs * fs,const char * comm)1320 int mnt_fs_append_comment(struct libmnt_fs *fs, const char *comm)
1321 {
1322 if (!fs)
1323 return -EINVAL;
1324
1325 return append_string(&fs->comment, comm);
1326 }
1327
1328 /**
1329 * mnt_fs_match_target:
1330 * @fs: filesystem
1331 * @target: mountpoint path
1332 * @cache: tags/paths cache or NULL
1333 *
1334 * Possible are three attempts:
1335 * 1) compare @target with @fs->target
1336 *
1337 * 2) realpath(@target) with @fs->target
1338 *
1339 * 3) realpath(@target) with realpath(@fs->target) if @fs is not from
1340 * /proc/self/mountinfo.
1341 *
1342 * However, if mnt_cache_set_targets(cache, mtab) was called, and the
1343 * path @target or @fs->target is found in the @mtab, the canonicalization is
1344 * is not performed (see mnt_resolve_target()).
1345 *
1346 * The 2nd and 3rd attempts are not performed when @cache is NULL.
1347 *
1348 * Returns: 1 if @fs target is equal to @target, else 0.
1349 */
mnt_fs_match_target(struct libmnt_fs * fs,const char * target,struct libmnt_cache * cache)1350 int mnt_fs_match_target(struct libmnt_fs *fs, const char *target,
1351 struct libmnt_cache *cache)
1352 {
1353 int rc = 0;
1354
1355 if (!fs || !target || !fs->target)
1356 return 0;
1357
1358 /* 1) native paths */
1359 rc = mnt_fs_streq_target(fs, target);
1360
1361 if (!rc && cache) {
1362 /* 2) - canonicalized and non-canonicalized */
1363 char *cn = mnt_resolve_target(target, cache);
1364 rc = (cn && mnt_fs_streq_target(fs, cn));
1365
1366 /* 3) - canonicalized and canonicalized */
1367 if (!rc && cn && !mnt_fs_is_kernel(fs) && !mnt_fs_is_swaparea(fs)) {
1368 char *tcn = mnt_resolve_target(fs->target, cache);
1369 rc = (tcn && strcmp(cn, tcn) == 0);
1370 }
1371 }
1372
1373 return rc;
1374 }
1375
1376 /**
1377 * mnt_fs_match_source:
1378 * @fs: filesystem
1379 * @source: tag or path (device or so) or NULL
1380 * @cache: tags/paths cache or NULL
1381 *
1382 * Four attempts are possible:
1383 * 1) compare @source with @fs->source
1384 * 2) compare realpath(@source) with @fs->source
1385 * 3) compare realpath(@source) with realpath(@fs->source)
1386 * 4) compare realpath(@source) with evaluated tag from @fs->source
1387 *
1388 * The 2nd, 3rd and 4th attempts are not performed when @cache is NULL. The
1389 * 2nd and 3rd attempts are not performed if @fs->source is tag.
1390 *
1391 * Returns: 1 if @fs source is equal to @source, else 0.
1392 */
mnt_fs_match_source(struct libmnt_fs * fs,const char * source,struct libmnt_cache * cache)1393 int mnt_fs_match_source(struct libmnt_fs *fs, const char *source,
1394 struct libmnt_cache *cache)
1395 {
1396 char *cn;
1397 const char *src, *t, *v;
1398
1399 if (!fs)
1400 return 0;
1401
1402 /* 1) native paths... */
1403 if (mnt_fs_streq_srcpath(fs, source) == 1)
1404 return 1;
1405
1406 if (!source || !fs->source)
1407 return 0;
1408
1409 /* ... and tags */
1410 if (fs->tagname && strcmp(source, fs->source) == 0)
1411 return 1;
1412
1413 if (!cache)
1414 return 0;
1415 if (fs->flags & (MNT_FS_NET | MNT_FS_PSEUDO))
1416 return 0;
1417
1418 cn = mnt_resolve_spec(source, cache);
1419 if (!cn)
1420 return 0;
1421
1422 /* 2) canonicalized and native */
1423 src = mnt_fs_get_srcpath(fs);
1424 if (src && mnt_fs_streq_srcpath(fs, cn))
1425 return 1;
1426
1427 /* 3) canonicalized and canonicalized */
1428 if (src) {
1429 src = mnt_resolve_path(src, cache);
1430 if (src && !strcmp(cn, src))
1431 return 1;
1432 }
1433 if (src || mnt_fs_get_tag(fs, &t, &v))
1434 /* src path does not match and the tag is not defined */
1435 return 0;
1436
1437 /* read @source's tags to the cache */
1438 if (mnt_cache_read_tags(cache, cn) < 0) {
1439 if (errno == EACCES) {
1440 /* we don't have permissions to read TAGs from
1441 * @source, but can translate the @fs tag to devname.
1442 *
1443 * (because libblkid uses udev symlinks and this is
1444 * accessible for non-root uses)
1445 */
1446 char *x = mnt_resolve_tag(t, v, cache);
1447 if (x && !strcmp(x, cn))
1448 return 1;
1449 }
1450 return 0;
1451 }
1452
1453 /* 4) has the @source a tag that matches with the tag from @fs ? */
1454 if (mnt_cache_device_has_tag(cache, cn, t, v))
1455 return 1;
1456
1457 return 0;
1458 }
1459
1460 /**
1461 * mnt_fs_match_fstype:
1462 * @fs: filesystem
1463 * @types: filesystem name or comma delimited list of filesystems
1464 *
1465 * For more details see mnt_match_fstype().
1466 *
1467 * Returns: 1 if @fs type is matching to @types, else 0. The function returns
1468 * 0 when types is NULL.
1469 */
mnt_fs_match_fstype(struct libmnt_fs * fs,const char * types)1470 int mnt_fs_match_fstype(struct libmnt_fs *fs, const char *types)
1471 {
1472 return mnt_match_fstype(fs->fstype, types);
1473 }
1474
1475 /**
1476 * mnt_fs_match_options:
1477 * @fs: filesystem
1478 * @options: comma delimited list of options (and nooptions)
1479 *
1480 * For more details see mnt_match_options().
1481 *
1482 * Returns: 1 if @fs type is matching to @options, else 0. The function returns
1483 * 0 when types is NULL.
1484 */
mnt_fs_match_options(struct libmnt_fs * fs,const char * options)1485 int mnt_fs_match_options(struct libmnt_fs *fs, const char *options)
1486 {
1487 return mnt_match_options(mnt_fs_get_options(fs), options);
1488 }
1489
1490 /**
1491 * mnt_fs_print_debug
1492 * @fs: fstab/mtab/mountinfo entry
1493 * @file: file stream
1494 *
1495 * Returns: 0 on success or negative number in case of error.
1496 */
mnt_fs_print_debug(struct libmnt_fs * fs,FILE * file)1497 int mnt_fs_print_debug(struct libmnt_fs *fs, FILE *file)
1498 {
1499 if (!fs || !file)
1500 return -EINVAL;
1501 fprintf(file, "------ fs:\n");
1502 fprintf(file, "source: %s\n", mnt_fs_get_source(fs));
1503 fprintf(file, "target: %s\n", mnt_fs_get_target(fs));
1504 fprintf(file, "fstype: %s\n", mnt_fs_get_fstype(fs));
1505
1506 if (mnt_fs_get_options(fs))
1507 fprintf(file, "optstr: %s\n", mnt_fs_get_options(fs));
1508 if (mnt_fs_get_vfs_options(fs))
1509 fprintf(file, "VFS-optstr: %s\n", mnt_fs_get_vfs_options(fs));
1510 if (mnt_fs_get_fs_options(fs))
1511 fprintf(file, "FS-opstr: %s\n", mnt_fs_get_fs_options(fs));
1512 if (mnt_fs_get_user_options(fs))
1513 fprintf(file, "user-optstr: %s\n", mnt_fs_get_user_options(fs));
1514 if (mnt_fs_get_optional_fields(fs))
1515 fprintf(file, "optional-fields: '%s'\n", mnt_fs_get_optional_fields(fs));
1516 if (mnt_fs_get_attributes(fs))
1517 fprintf(file, "attributes: %s\n", mnt_fs_get_attributes(fs));
1518
1519 if (mnt_fs_get_root(fs))
1520 fprintf(file, "root: %s\n", mnt_fs_get_root(fs));
1521
1522 if (mnt_fs_get_swaptype(fs))
1523 fprintf(file, "swaptype: %s\n", mnt_fs_get_swaptype(fs));
1524 if (mnt_fs_get_size(fs))
1525 fprintf(file, "size: %jd\n", mnt_fs_get_size(fs));
1526 if (mnt_fs_get_usedsize(fs))
1527 fprintf(file, "usedsize: %jd\n", mnt_fs_get_usedsize(fs));
1528 if (mnt_fs_get_priority(fs))
1529 fprintf(file, "priority: %d\n", mnt_fs_get_priority(fs));
1530
1531 if (mnt_fs_get_bindsrc(fs))
1532 fprintf(file, "bindsrc: %s\n", mnt_fs_get_bindsrc(fs));
1533 if (mnt_fs_get_freq(fs))
1534 fprintf(file, "freq: %d\n", mnt_fs_get_freq(fs));
1535 if (mnt_fs_get_passno(fs))
1536 fprintf(file, "pass: %d\n", mnt_fs_get_passno(fs));
1537 if (mnt_fs_get_id(fs))
1538 fprintf(file, "id: %d\n", mnt_fs_get_id(fs));
1539 if (mnt_fs_get_parent_id(fs))
1540 fprintf(file, "parent: %d\n", mnt_fs_get_parent_id(fs));
1541 if (mnt_fs_get_devno(fs))
1542 fprintf(file, "devno: %d:%d\n", major(mnt_fs_get_devno(fs)),
1543 minor(mnt_fs_get_devno(fs)));
1544 if (mnt_fs_get_tid(fs))
1545 fprintf(file, "tid: %d\n", mnt_fs_get_tid(fs));
1546 if (mnt_fs_get_comment(fs))
1547 fprintf(file, "comment: '%s'\n", mnt_fs_get_comment(fs));
1548
1549 return 0;
1550 }
1551
1552 /**
1553 * mnt_free_mntent:
1554 * @mnt: mount entry
1555 *
1556 * Deallocates the "mntent.h" mount entry.
1557 */
mnt_free_mntent(struct mntent * mnt)1558 void mnt_free_mntent(struct mntent *mnt)
1559 {
1560 if (mnt) {
1561 free(mnt->mnt_fsname);
1562 free(mnt->mnt_dir);
1563 free(mnt->mnt_type);
1564 free(mnt->mnt_opts);
1565 free(mnt);
1566 }
1567 }
1568
1569 /**
1570 * mnt_fs_to_mntent:
1571 * @fs: filesystem
1572 * @mnt: mount description (as described in mntent.h)
1573 *
1574 * Copies the information from @fs to struct mntent @mnt. If @mnt is already set,
1575 * then the struct mntent items are reallocated and updated. See also
1576 * mnt_free_mntent().
1577 *
1578 * Returns: 0 on success and a negative number in case of error.
1579 */
mnt_fs_to_mntent(struct libmnt_fs * fs,struct mntent ** mnt)1580 int mnt_fs_to_mntent(struct libmnt_fs *fs, struct mntent **mnt)
1581 {
1582 int rc;
1583 struct mntent *m;
1584
1585 if (!fs || !mnt)
1586 return -EINVAL;
1587
1588 m = *mnt;
1589 if (!m) {
1590 m = calloc(1, sizeof(*m));
1591 if (!m)
1592 return -ENOMEM;
1593 }
1594
1595 if ((rc = update_str(&m->mnt_fsname, mnt_fs_get_source(fs))))
1596 goto err;
1597 if ((rc = update_str(&m->mnt_dir, mnt_fs_get_target(fs))))
1598 goto err;
1599 if ((rc = update_str(&m->mnt_type, mnt_fs_get_fstype(fs))))
1600 goto err;
1601
1602 errno = 0;
1603 m->mnt_opts = mnt_fs_strdup_options(fs);
1604 if (!m->mnt_opts && errno) {
1605 rc = -errno;
1606 goto err;
1607 }
1608
1609 m->mnt_freq = mnt_fs_get_freq(fs);
1610 m->mnt_passno = mnt_fs_get_passno(fs);
1611
1612 if (!m->mnt_fsname) {
1613 m->mnt_fsname = strdup("none");
1614 if (!m->mnt_fsname)
1615 goto err;
1616 }
1617 *mnt = m;
1618
1619 return 0;
1620 err:
1621 if (m != *mnt)
1622 mnt_free_mntent(m);
1623 return rc;
1624 }
1625