]> git.ipfire.org Git - thirdparty/util-linux.git/blame_incremental - libmount/src/fs.c
more: Use ul_strtou16() in a robust way
[thirdparty/util-linux.git] / libmount / src / fs.c
... / ...
CommitLineData
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, 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 */
34struct libmnt_fs *mnt_new_fs(void)
35{
36 struct libmnt_fs *fs = calloc(1, sizeof(*fs));
37
38 if (!fs)
39 return NULL;
40
41 fs->refcount = 1;
42 INIT_LIST_HEAD(&fs->ents);
43 DBG(FS, ul_debugobj(fs, "alloc"));
44 return fs;
45}
46
47/**
48 * mnt_free_fs:
49 * @fs: fs pointer
50 *
51 * Deallocates the fs. This function does not care about reference count. Don't
52 * use this function directly -- it's better to use mnt_unref_fs().
53 *
54 * The reference counting is supported since util-linux v2.24.
55 */
56void mnt_free_fs(struct libmnt_fs *fs)
57{
58 if (!fs)
59 return;
60
61 DBG(FS, ul_debugobj(fs, "free [refcount=%d]", fs->refcount));
62
63 mnt_reset_fs(fs);
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 int ref;
76
77 if (!fs)
78 return;
79
80 ref = fs->refcount;
81
82 list_del(&fs->ents);
83 free(fs->source);
84 free(fs->bindsrc);
85 free(fs->tagname);
86 free(fs->tagval);
87 free(fs->root);
88 free(fs->swaptype);
89 free(fs->target);
90 free(fs->fstype);
91 free(fs->optstr);
92 free(fs->vfs_optstr);
93 free(fs->fs_optstr);
94 free(fs->user_optstr);
95 free(fs->attrs);
96 free(fs->opt_fields);
97 free(fs->comment);
98
99 mnt_unref_optlist(fs->optlist);
100 fs->optlist = NULL;
101
102 fs->opts_age = 0;
103 fs->propagation = 0;
104
105 mnt_unref_statmnt(fs->stmnt);
106 fs->stmnt = NULL;
107 fs->stmnt_done = 0;
108
109 memset(fs, 0, sizeof(*fs));
110 INIT_LIST_HEAD(&fs->ents);
111 fs->refcount = ref;
112}
113
114/**
115 * mnt_ref_fs:
116 * @fs: fs pointer
117 *
118 * Increments reference counter.
119 */
120void mnt_ref_fs(struct libmnt_fs *fs)
121{
122 if (fs) {
123 fs->refcount++;
124 /*DBG(FS, ul_debugobj(fs, "ref=%d", fs->refcount));*/
125 }
126}
127
128/**
129 * mnt_unref_fs:
130 * @fs: fs pointer
131 *
132 * De-increments reference counter, on zero the @fs is automatically
133 * deallocated by mnt_free_fs().
134 */
135void mnt_unref_fs(struct libmnt_fs *fs)
136{
137 if (fs) {
138 fs->refcount--;
139 /*DBG(FS, ul_debugobj(fs, "unref=%d", fs->refcount));*/
140 if (fs->refcount <= 0)
141 mnt_free_fs(fs);
142 }
143}
144
145static inline int update_str(char **dest, const char *src)
146{
147 size_t sz;
148 char *x;
149
150 assert(dest);
151
152 if (!src) {
153 free(*dest);
154 *dest = NULL;
155 return 0; /* source (old) is empty */
156 }
157
158 sz = strlen(src) + 1;
159 x = realloc(*dest, sz);
160 if (!x)
161 return -ENOMEM;
162 *dest = x;
163 memcpy(*dest, src, sz);
164 return 0;
165}
166
167/* This function does NOT overwrite (replace) the string in @new, the string in
168 * @new has to be NULL otherwise this is no-op. */
169static inline int cpy_str_at_offset(void *new, const void *old, size_t offset)
170{
171 char **o = (char **) ((char *) old + offset);
172 char **n = (char **) ((char *) new + offset);
173
174 if (*n)
175 return 0; /* already set, don't overwrite */
176
177 return update_str(n, *o);
178}
179
180static inline int sync_opts_from_optlist(struct libmnt_fs *fs, struct libmnt_optlist *ol)
181{
182 unsigned int age;
183
184 assert(fs);
185 assert(ol);
186
187 age = mnt_optlist_get_age(ol);
188 if (age != fs->opts_age) {
189 const char *p;
190 int rc;
191
192 /* All options */
193 rc = mnt_optlist_get_optstr(ol, &p, NULL, 0);
194 if (!rc)
195 rc = strdup_to_struct_member(fs, optstr, p);
196
197 /* FS options */
198 if (!rc)
199 rc = mnt_optlist_get_optstr(ol, &p, NULL, MNT_OL_FLTR_UNKNOWN);
200 if (!rc)
201 rc = strdup_to_struct_member(fs, fs_optstr, p);
202
203 /* VFS options */
204 if (!rc)
205 rc = mnt_optlist_get_optstr(ol, &p, mnt_get_builtin_optmap(MNT_LINUX_MAP), 0);
206 if (!rc)
207 rc = strdup_to_struct_member(fs, vfs_optstr, p);
208
209 /* Userspace options */
210 if (!rc)
211 rc = mnt_optlist_get_optstr(ol, &p, mnt_get_builtin_optmap(MNT_USERSPACE_MAP), 0);
212 if (!rc)
213 rc = strdup_to_struct_member(fs, user_optstr, p);
214
215 if (rc) {
216 DBG(FS, ul_debugobj(fs, "sync failed [rc=%d]", rc));
217 return rc;
218 } else {
219 DBG(FS, ul_debugobj(fs, "synced: "
220 "vfs: '%s' fs: '%s' user: '%s', optstr: '%s'",
221 fs->vfs_optstr, fs->fs_optstr, fs->user_optstr, fs->optstr));
222 fs->opts_age = age;
223 }
224 }
225 return 0;
226}
227
228/* If @optlist is not NULL then @fs will read all option strings from @optlist.
229 * It means that mnt_fs_get_*_options() won't be read-only operations. */
230int mnt_fs_follow_optlist(struct libmnt_fs *fs, struct libmnt_optlist *ol)
231{
232 assert(fs);
233
234 if (fs->optlist == ol)
235 return 0;
236 if (fs->optlist)
237 mnt_unref_optlist(fs->optlist);
238
239 fs->opts_age = 0;
240 fs->optlist = ol;
241
242 if (ol)
243 mnt_ref_optlist(ol);
244 return 0;
245}
246
247/**
248 * mnt_copy_fs:
249 * @dest: destination FS
250 * @src: source FS
251 *
252 * If @dest is NULL, then a new FS is allocated, if any @dest field is already
253 * set, then the field is NOT overwritten.
254 *
255 * This function does not copy userdata (se mnt_fs_set_userdata()). A new copy is
256 * not linked with any existing mnt_tab or optlist.
257 *
258 * Returns: @dest or NULL in case of error
259 */
260struct libmnt_fs *mnt_copy_fs(struct libmnt_fs *dest,
261 const struct libmnt_fs *src)
262{
263 const struct libmnt_fs *org = dest;
264
265 if (!src)
266 return NULL;
267 if (!dest) {
268 dest = mnt_new_fs();
269 if (!dest)
270 return NULL;
271
272 dest->tab = NULL;
273 }
274
275 dest->id = src->id;
276 dest->parent = src->parent;
277 dest->devno = src->devno;
278 dest->tid = src->tid;
279
280 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, source)))
281 goto err;
282 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, tagname)))
283 goto err;
284 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, tagval)))
285 goto err;
286 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, root)))
287 goto err;
288 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, swaptype)))
289 goto err;
290 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, target)))
291 goto err;
292 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, fstype)))
293 goto err;
294 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, optstr)))
295 goto err;
296 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, vfs_optstr)))
297 goto err;
298 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, fs_optstr)))
299 goto err;
300 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, user_optstr)))
301 goto err;
302 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, attrs)))
303 goto err;
304 if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, bindsrc)))
305 goto err;
306
307 dest->freq = src->freq;
308 dest->passno = src->passno;
309 dest->flags = src->flags;
310 dest->size = src->size;
311 dest->usedsize = src->usedsize;
312 dest->priority = src->priority;
313
314 return dest;
315err:
316 if (!org)
317 mnt_free_fs(dest);
318 return NULL;
319}
320
321/*
322 * This function copies all @fs description except information that does not
323 * belong to /etc/mtab (e.g. VFS and userspace mount options with MNT_NOMTAB
324 * mask).
325 *
326 * Returns: copy of @fs.
327 */
328struct libmnt_fs *mnt_copy_mtab_fs(struct libmnt_fs *fs)
329{
330 struct libmnt_fs *n = mnt_new_fs();
331
332 assert(fs);
333 if (!n)
334 return NULL;
335 if (fs->optlist)
336 sync_opts_from_optlist(fs, fs->optlist);
337
338 if (strdup_between_structs(n, fs, source))
339 goto err;
340 if (strdup_between_structs(n, fs, target))
341 goto err;
342 if (strdup_between_structs(n, fs, fstype))
343 goto err;
344
345 if (fs->vfs_optstr) {
346 char *p = NULL;
347 mnt_optstr_get_options(fs->vfs_optstr, &p,
348 mnt_get_builtin_optmap(MNT_LINUX_MAP),
349 MNT_NOMTAB);
350 n->vfs_optstr = p;
351 }
352
353 if (fs->user_optstr) {
354 char *p = NULL;
355 mnt_optstr_get_options(fs->user_optstr, &p,
356 mnt_get_builtin_optmap(MNT_USERSPACE_MAP),
357 MNT_NOMTAB);
358 n->user_optstr = p;
359 }
360
361 if (strdup_between_structs(n, fs, fs_optstr))
362 goto err;
363
364 /* we cannot copy original optstr, the new optstr has to be without
365 * non-mtab options -- so, let's generate a new string */
366 n->optstr = mnt_fs_strdup_options(n);
367
368 n->freq = fs->freq;
369 n->passno = fs->passno;
370 n->flags = fs->flags;
371
372 return n;
373err:
374 mnt_free_fs(n);
375 return NULL;
376
377}
378
379/**
380 * mnt_fs_get_userdata:
381 * @fs: struct libmnt_file instance
382 *
383 * Returns: private data set by mnt_fs_set_userdata() or NULL.
384 */
385void *mnt_fs_get_userdata(struct libmnt_fs *fs)
386{
387 if (!fs)
388 return NULL;
389 return fs->userdata;
390}
391
392/**
393 * mnt_fs_set_userdata:
394 * @fs: struct libmnt_file instance
395 * @data: user data
396 *
397 * The "userdata" are library independent data.
398 *
399 * Returns: 0 or negative number in case of error (if @fs is NULL).
400 */
401int mnt_fs_set_userdata(struct libmnt_fs *fs, void *data)
402{
403 if (!fs)
404 return -EINVAL;
405 fs->userdata = data;
406 return 0;
407}
408
409/**
410 * mnt_fs_get_srcpath:
411 * @fs: struct libmnt_file (fstab/mtab/mountinfo) fs
412 *
413 * The mount "source path" is:
414 * - a directory for 'bind' mounts (in fstab or mtab only)
415 * - a device name for standard mounts
416 *
417 * See also mnt_fs_get_tag() and mnt_fs_get_source().
418 *
419 * Returns: mount source path or NULL in case of error or when the path
420 * is not defined.
421 */
422const char *mnt_fs_get_srcpath(struct libmnt_fs *fs)
423{
424 if (!fs)
425 return NULL;
426
427 /* fstab-like fs */
428 if (fs->tagname)
429 return NULL; /* the source contains a "NAME=value" */
430
431 return mnt_fs_get_source(fs);
432}
433
434/**
435 * mnt_fs_get_source:
436 * @fs: struct libmnt_file (fstab/mtab/mountinfo) fs
437 *
438 * Returns: mount source. Note that the source could be unparsed TAG
439 * (LABEL/UUID). See also mnt_fs_get_srcpath() and mnt_fs_get_tag().
440 */
441const char *mnt_fs_get_source(struct libmnt_fs *fs)
442{
443 if (!fs)
444 return NULL;
445
446#ifdef HAVE_STATMOUNT_API
447 mnt_fs_try_statmount(fs, source, STATMOUNT_SB_SOURCE);
448#endif
449 return fs->source;
450}
451
452/*
453 * Used by the parser ONLY (@source has to be freed on error)
454 */
455int __mnt_fs_set_source_ptr(struct libmnt_fs *fs, char *source)
456{
457 char *t = NULL, *v = NULL;
458
459 assert(fs);
460
461 if (source && blkid_parse_tag_string(source, &t, &v) == 0 &&
462 !mnt_valid_tagname(t)) {
463 /* parsable but unknown tag -- ignore */
464 free(t);
465 free(v);
466 t = v = NULL;
467 }
468
469 if (fs->source != source)
470 free(fs->source);
471
472 free(fs->tagname);
473 free(fs->tagval);
474
475 fs->source = source;
476 fs->tagname = t;
477 fs->tagval = v;
478 return 0;
479}
480
481/**
482 * mnt_fs_set_source:
483 * @fs: fstab/mtab/mountinfo entry
484 * @source: new source
485 *
486 * This function creates a private copy (strdup()) of @source.
487 *
488 * Returns: 0 on success or negative number in case of error.
489 */
490int mnt_fs_set_source(struct libmnt_fs *fs, const char *source)
491{
492 char *p = NULL;
493 int rc;
494
495 if (!fs)
496 return -EINVAL;
497
498 if (source) {
499 p = strdup(source);
500 if (!p)
501 return -ENOMEM;
502 }
503
504 rc = __mnt_fs_set_source_ptr(fs, p);
505 if (rc)
506 free(p);
507 return rc;
508}
509
510/**
511 * mnt_fs_streq_srcpath:
512 * @fs: fs
513 * @path: source path
514 *
515 * Compares @fs source path with @path. The redundant slashes are ignored.
516 * This function compares strings and does not canonicalize the paths.
517 * See also more heavy and generic mnt_fs_match_source().
518 *
519 * Returns: 1 if @fs source path equal to @path, otherwise 0.
520 */
521int mnt_fs_streq_srcpath(struct libmnt_fs *fs, const char *path)
522{
523 const char *p;
524
525 if (!fs)
526 return 0;
527
528 p = mnt_fs_get_srcpath(fs);
529
530 if (!mnt_fs_is_pseudofs(fs))
531 return streq_paths(p, path);
532
533 if (!p && !path)
534 return 1;
535
536 return p && path && strcmp(p, path) == 0;
537}
538
539/**
540 * mnt_fs_get_table:
541 * @fs: table entry
542 * @tb: table that contains @fs
543 *
544 * Returns: 0 or negative number on error (if @fs or @tb is NULL).
545 *
546 * Since: 2.34
547 */
548int mnt_fs_get_table(struct libmnt_fs *fs, struct libmnt_table **tb)
549{
550 if (!fs || !tb)
551 return -EINVAL;
552
553 *tb = fs->tab;
554 return 0;
555}
556
557/**
558 * mnt_fs_streq_target:
559 * @fs: fs
560 * @path: mount point
561 *
562 * Compares @fs target path with @path. The redundant slashes are ignored.
563 * This function compares strings and does not canonicalize the paths.
564 * See also more generic mnt_fs_match_target().
565 *
566 * Returns: 1 if @fs target path equal to @path, otherwise 0.
567 */
568int mnt_fs_streq_target(struct libmnt_fs *fs, const char *path)
569{
570 return fs && streq_paths(mnt_fs_get_target(fs), path);
571}
572
573/**
574 * mnt_fs_get_tag:
575 * @fs: fs
576 * @name: returns pointer to NAME string
577 * @value: returns pointer to VALUE string
578 *
579 * "TAG" is NAME=VALUE (e.g. LABEL=foo)
580 *
581 * The TAG is the first column in the fstab file. The TAG or "srcpath" always has
582 * to be set for all entries.
583 *
584 * See also mnt_fs_get_source().
585 *
586 * <informalexample>
587 * <programlisting>
588 * char *src;
589 * struct libmnt_fs *fs = mnt_table_find_target(tb, "/home", MNT_ITER_FORWARD);
590 *
591 * if (!fs)
592 * goto err;
593 *
594 * src = mnt_fs_get_srcpath(fs);
595 * if (!src) {
596 * char *tag, *val;
597 * if (mnt_fs_get_tag(fs, &tag, &val) == 0)
598 * printf("%s: %s\n", tag, val); // LABEL or UUID
599 * } else
600 * printf("device: %s\n", src); // device or bind path
601 * </programlisting>
602 * </informalexample>
603 *
604 * Returns: 0 on success or negative number in case a TAG is not defined.
605 */
606int mnt_fs_get_tag(struct libmnt_fs *fs, const char **name, const char **value)
607{
608 if (fs == NULL || !fs->tagname)
609 return -EINVAL;
610 if (name)
611 *name = fs->tagname;
612 if (value)
613 *value = fs->tagval;
614 return 0;
615}
616
617/**
618 * mnt_fs_get_target:
619 * @fs: fstab/mtab/mountinfo entry pointer
620 *
621 * Returns: pointer to mountpoint path or NULL
622 */
623const char *mnt_fs_get_target(struct libmnt_fs *fs)
624{
625 if (!fs)
626 return NULL;
627#ifdef HAVE_STATMOUNT_API
628 mnt_fs_try_statmount(fs, target, STATMOUNT_MNT_POINT);
629#endif
630 return fs->target;;
631}
632
633/**
634 * mnt_fs_set_target:
635 * @fs: fstab/mtab/mountinfo entry
636 * @tgt: mountpoint
637 *
638 * This function creates a private copy (strdup()) of @tgt.
639 *
640 * Returns: 0 on success or negative number in case of error.
641 */
642int mnt_fs_set_target(struct libmnt_fs *fs, const char *tgt)
643{
644 return strdup_to_struct_member(fs, target, tgt);
645}
646
647int __mnt_fs_set_target_ptr(struct libmnt_fs *fs, char *tgt)
648{
649 assert(fs);
650
651 free(fs->target);
652 fs->target = tgt;
653 return 0;
654}
655
656static int mnt_fs_get_flags(struct libmnt_fs *fs)
657{
658 return fs ? fs->flags : 0;
659}
660
661/**
662 * mnt_fs_get_propagation:
663 * @fs: mountinfo entry
664 * @flags: returns propagation MS_* flags as present in the mountinfo file
665 *
666 * Note that this function sets @flags to zero if no propagation flags are found
667 * in the mountinfo file. The kernel default is MS_PRIVATE, this flag is not stored
668 * in the mountinfo file.
669 *
670 * Returns: 0 on success or negative number in case of error.
671 */
672int mnt_fs_get_propagation(struct libmnt_fs *fs, unsigned long *flags)
673{
674 if (!fs || !flags)
675 return -EINVAL;
676#ifdef HAVE_STATMOUNT_API
677 mnt_fs_try_statmount(fs, propagation, STATMOUNT_MNT_BASIC);
678#endif
679 if (!fs->propagation && fs->opt_fields) {
680 /*
681 * The optional fields format is incompatible with mount options
682 * ... we have to parse the field here.
683 */
684 fs->propagation |= strstr(fs->opt_fields, "shared:") ?
685 MS_SHARED : MS_PRIVATE;
686
687 if (strstr(fs->opt_fields, "master:"))
688 fs->propagation |= MS_SLAVE;
689 if (strstr(fs->opt_fields, "unbindable"))
690 fs->propagation |= MS_UNBINDABLE;
691 }
692
693 *flags = fs->propagation;
694
695 return 0;
696}
697
698/**
699 * mnt_fs_is_kernel:
700 * @fs: filesystem
701 *
702 * Returns: 1 if the filesystem description is read from kernel e.g. /proc/mounts.
703 */
704int mnt_fs_is_kernel(struct libmnt_fs *fs)
705{
706 return mnt_fs_get_flags(fs) & MNT_FS_KERNEL ? 1 : 0;
707}
708
709/**
710 * mnt_fs_is_swaparea:
711 * @fs: filesystem
712 *
713 * Returns: 1 if the filesystem uses "swap" as a type
714 */
715int mnt_fs_is_swaparea(struct libmnt_fs *fs)
716{
717 return mnt_fs_get_flags(fs) & MNT_FS_SWAP ? 1 : 0;
718}
719
720/**
721 * mnt_fs_is_pseudofs:
722 * @fs: filesystem
723 *
724 * Returns: 1 if the filesystem is a pseudo fs type (proc, cgroups)
725 */
726int mnt_fs_is_pseudofs(struct libmnt_fs *fs)
727{
728 if (!fs)
729 return 0;
730#ifdef HAVE_STATMOUNT_API
731 mnt_fs_try_statmount(fs, fstype, STATMOUNT_FS_TYPE);
732#endif
733 return mnt_fs_get_flags(fs) & MNT_FS_PSEUDO ? 1 : 0;
734}
735
736/**
737 * mnt_fs_is_netfs:
738 * @fs: filesystem
739 *
740 * Returns: 1 if the filesystem is a network filesystem
741 */
742int mnt_fs_is_netfs(struct libmnt_fs *fs)
743{
744 if (!fs)
745 return 0;
746#ifdef HAVE_STATMOUNT_API
747 mnt_fs_try_statmount(fs, fstype, STATMOUNT_FS_TYPE);
748#endif
749 return mnt_fs_get_flags(fs) & MNT_FS_NET ? 1 : 0;
750}
751
752/**
753 * mnt_fs_is_regularfs:
754 * @fs: filesystem
755 *
756 * Returns: 1 if the filesystem is a regular filesystem (not network or pseudo filesystem).
757 *
758 * Since: 2.38
759 */
760int mnt_fs_is_regularfs(struct libmnt_fs *fs)
761{
762 return !(mnt_fs_is_pseudofs(fs)
763 || mnt_fs_is_netfs(fs)
764 || mnt_fs_is_swaparea(fs));
765}
766
767/**
768 * mnt_fs_get_fstype:
769 * @fs: fstab/mtab/mountinfo entry pointer
770 *
771 * Returns: pointer to filesystem type.
772 */
773const char *mnt_fs_get_fstype(struct libmnt_fs *fs)
774{
775 if (!fs)
776 return NULL;
777#ifdef HAVE_STATMOUNT_API
778 mnt_fs_try_statmount(fs, fstype, STATMOUNT_FS_TYPE);
779#endif
780 return fs->fstype;
781}
782
783/* Used by the struct libmnt_file parser only */
784int __mnt_fs_set_fstype_ptr(struct libmnt_fs *fs, char *fstype)
785{
786 assert(fs);
787
788 if (fstype != fs->fstype)
789 free(fs->fstype);
790
791 fs->fstype = fstype;
792 fs->flags &= ~MNT_FS_PSEUDO;
793 fs->flags &= ~MNT_FS_NET;
794 fs->flags &= ~MNT_FS_SWAP;
795
796 /* save info about pseudo filesystems */
797 if (fs->fstype) {
798 if (mnt_fstype_is_pseudofs(fs->fstype))
799 fs->flags |= MNT_FS_PSEUDO;
800 else if (mnt_fstype_is_netfs(fs->fstype))
801 fs->flags |= MNT_FS_NET;
802 else if (!strcmp(fs->fstype, "swap"))
803 fs->flags |= MNT_FS_SWAP;
804 }
805 return 0;
806}
807
808/**
809 * mnt_fs_set_fstype:
810 * @fs: fstab/mtab/mountinfo entry
811 * @fstype: filesystem type
812 *
813 * This function creates a private copy (strdup()) of @fstype.
814 *
815 * Returns: 0 on success or negative number in case of error.
816 */
817int mnt_fs_set_fstype(struct libmnt_fs *fs, const char *fstype)
818{
819 char *p = NULL;
820
821 if (!fs)
822 return -EINVAL;
823 if (fstype) {
824 p = strdup(fstype);
825 if (!p)
826 return -ENOMEM;
827 }
828 return __mnt_fs_set_fstype_ptr(fs, p);
829}
830
831/*
832 * Merges @vfs and @fs options strings into a new string. This function cares
833 * about 'ro/rw' options. The 'ro' is always used if @vfs or @fs is read-only.
834 */
835static char *merge_optstr(const char *vfs, const char *fs)
836{
837 char *res, *p;
838 size_t sz;
839 int ro = 0, rw = 0;
840
841 if (!vfs && !fs)
842 return NULL;
843 if (!vfs || !fs)
844 return strdup(fs ? fs : vfs);
845 if (!strcmp(vfs, fs))
846 return strdup(vfs); /* e.g. "aaa" and "aaa" */
847
848 /* leave space for the leading "r[ow],", "," and the trailing zero */
849 sz = strlen(vfs) + strlen(fs) + 5;
850 res = malloc(sz);
851 if (!res)
852 return NULL;
853 p = res + 3; /* make a room for rw/ro flag */
854
855 snprintf(p, sz - 3, "%s,%s", vfs, fs);
856
857 /* remove 'rw' flags */
858 rw += !mnt_optstr_remove_option(&p, "rw"); /* from vfs */
859 rw += !mnt_optstr_remove_option(&p, "rw"); /* from fs */
860
861 /* remove 'ro' flags if necessary */
862 if (rw != 2) {
863 ro += !mnt_optstr_remove_option(&p, "ro");
864 if (ro + rw < 2)
865 ro += !mnt_optstr_remove_option(&p, "ro");
866 }
867
868 if (!strlen(p))
869 memcpy(res, ro ? "ro" : "rw", 3);
870 else
871 memcpy(res, ro ? "ro," : "rw,", 3);
872 return res;
873}
874
875static char *fs_strdup_options(struct libmnt_fs *fs)
876{
877 char *res;
878
879 errno = 0;
880 if (fs->optstr)
881 return strdup(fs->optstr);
882
883 res = merge_optstr(fs->vfs_optstr, fs->fs_optstr);
884 if (!res && errno)
885 return NULL;
886 if (fs->user_optstr &&
887 mnt_optstr_append_option(&res, fs->user_optstr, NULL)) {
888 free(res);
889 res = NULL;
890 }
891 return res;
892}
893
894/**
895 * mnt_fs_strdup_options:
896 * @fs: fstab/mtab/mountinfo entry pointer
897 *
898 * Merges all mount options (VFS, FS and userspace) to one options string
899 * and returns the result. This function does not modify @fs.
900 *
901 * Returns: pointer to string (can be freed by free(3)) or NULL in case of error.
902 */
903char *mnt_fs_strdup_options(struct libmnt_fs *fs)
904{
905 if (!fs)
906 return NULL;
907 if (fs->optlist)
908 sync_opts_from_optlist(fs, fs->optlist);
909#ifdef HAVE_STATMOUNT_API
910 else
911 mnt_fs_try_statmount(fs, optstr, STATMOUNT_SB_BASIC
912 | STATMOUNT_MNT_BASIC | STATMOUNT_MNT_OPTS);
913#endif
914 return fs_strdup_options(fs);
915
916}
917
918/**
919 * mnt_fs_get_options:
920 * @fs: fstab/mtab/mountinfo entry pointer
921 *
922 * Returns: pointer to string or NULL in case of error.
923 */
924const char *mnt_fs_get_options(struct libmnt_fs *fs)
925{
926 if (!fs)
927 return NULL;
928 if (fs->optlist)
929 sync_opts_from_optlist(fs, fs->optlist);
930#ifdef HAVE_STATMOUNT_API
931 else {
932 mnt_fs_try_statmount(fs, optstr, STATMOUNT_SB_BASIC
933 | STATMOUNT_MNT_BASIC | STATMOUNT_MNT_OPTS);
934 if (!fs->optstr)
935 fs->optstr = fs_strdup_options(fs);
936 }
937#endif
938 return fs->optstr;
939}
940
941/**
942 * mnt_fs_get_optional_fields
943 * @fs: mountinfo entry pointer
944 *
945 * Returns: pointer to string with mountinfo optional fields
946 * or NULL in case of error.
947 */
948const char *mnt_fs_get_optional_fields(struct libmnt_fs *fs)
949{
950 return fs ? fs->opt_fields : NULL;
951}
952
953/**
954 * mnt_fs_set_options:
955 * @fs: fstab/mtab/mountinfo entry pointer
956 * @optstr: options string
957 *
958 * Splits @optstr to VFS, FS and userspace mount options and updates relevant
959 * parts of @fs.
960 *
961 * Returns: 0 on success, or negative number in case of error.
962 */
963int mnt_fs_set_options(struct libmnt_fs *fs, const char *optstr)
964{
965 char *v = NULL, *f = NULL, *u = NULL, *n = NULL;
966
967 if (!fs)
968 return -EINVAL;
969
970 if (fs->optlist) {
971 fs->opts_age = 0;
972 return mnt_optlist_set_optstr(fs->optlist, optstr, NULL);
973 }
974
975 if (optstr) {
976 int rc = mnt_split_optstr(optstr, &u, &v, &f, 0, 0);
977 if (rc)
978 return rc;
979 n = strdup(optstr);
980 if (!n) {
981 free(u);
982 free(v);
983 free(f);
984 return -ENOMEM;
985 }
986 }
987
988 free(fs->fs_optstr);
989 free(fs->vfs_optstr);
990 free(fs->user_optstr);
991 free(fs->optstr);
992
993 fs->fs_optstr = f;
994 fs->vfs_optstr = v;
995 fs->user_optstr = u;
996 fs->optstr = n;
997
998 return 0;
999}
1000
1001/**
1002 * mnt_fs_append_options:
1003 * @fs: fstab/mtab/mountinfo entry
1004 * @optstr: mount options
1005 *
1006 * Parses (splits) @optstr and appends results to VFS, FS and userspace lists
1007 * of options.
1008 *
1009 * If @optstr is NULL, then @fs is not modified and 0 is returned.
1010 *
1011 * Returns: 0 on success or negative number in case of error.
1012 */
1013int mnt_fs_append_options(struct libmnt_fs *fs, const char *optstr)
1014{
1015 char *v = NULL, *f = NULL, *u = NULL;
1016 int rc;
1017
1018 if (!fs)
1019 return -EINVAL;
1020 if (!optstr)
1021 return 0;
1022 if (fs->optlist) {
1023 fs->opts_age = 0;
1024 return mnt_optlist_append_optstr(fs->optlist, optstr, NULL);
1025 }
1026
1027 rc = mnt_split_optstr(optstr, &u, &v, &f, 0, 0);
1028 if (rc)
1029 return rc;
1030
1031 if (!rc && v)
1032 rc = mnt_optstr_append_option(&fs->vfs_optstr, v, NULL);
1033 if (!rc && f)
1034 rc = mnt_optstr_append_option(&fs->fs_optstr, f, NULL);
1035 if (!rc && u)
1036 rc = mnt_optstr_append_option(&fs->user_optstr, u, NULL);
1037 if (!rc)
1038 rc = mnt_optstr_append_option(&fs->optstr, optstr, NULL);
1039
1040 free(v);
1041 free(f);
1042 free(u);
1043
1044 return rc;
1045}
1046
1047/**
1048 * mnt_fs_prepend_options:
1049 * @fs: fstab/mtab/mountinfo entry
1050 * @optstr: mount options
1051 *
1052 * Parses (splits) @optstr and prepends the results to VFS, FS and userspace lists
1053 * of options.
1054 *
1055 * If @optstr is NULL, then @fs is not modified and 0 is returned.
1056 *
1057 * Returns: 0 on success or negative number in case of error.
1058 */
1059int mnt_fs_prepend_options(struct libmnt_fs *fs, const char *optstr)
1060{
1061 char *v = NULL, *f = NULL, *u = NULL;
1062 int rc;
1063
1064 if (!fs)
1065 return -EINVAL;
1066 if (!optstr)
1067 return 0;
1068
1069 if (fs->optlist) {
1070 fs->opts_age = 0;
1071 return mnt_optlist_prepend_optstr(fs->optlist, optstr, NULL);
1072 }
1073
1074 rc = mnt_split_optstr(optstr, &u, &v, &f, 0, 0);
1075 if (rc)
1076 return rc;
1077
1078 if (!rc && v)
1079 rc = mnt_optstr_prepend_option(&fs->vfs_optstr, v, NULL);
1080 if (!rc && f)
1081 rc = mnt_optstr_prepend_option(&fs->fs_optstr, f, NULL);
1082 if (!rc && u)
1083 rc = mnt_optstr_prepend_option(&fs->user_optstr, u, NULL);
1084 if (!rc)
1085 rc = mnt_optstr_prepend_option(&fs->optstr, optstr, NULL);
1086
1087 free(v);
1088 free(f);
1089 free(u);
1090
1091 return rc;
1092}
1093
1094
1095/**
1096 * mnt_fs_get_fs_options:
1097 * @fs: fstab/mtab/mountinfo entry pointer
1098 *
1099 * Returns: pointer to superblock (fs-depend) mount option string or NULL.
1100 */
1101const char *mnt_fs_get_fs_options(struct libmnt_fs *fs)
1102{
1103 if (!fs)
1104 return NULL;
1105 if (fs->optlist)
1106 sync_opts_from_optlist(fs, fs->optlist);
1107#ifdef HAVE_STATMOUNT_API
1108 else
1109 mnt_fs_try_statmount(fs, fs_optstr, STATMOUNT_SB_BASIC | STATMOUNT_MNT_OPTS);
1110#endif
1111 return fs->fs_optstr;
1112}
1113
1114/**
1115 * mnt_fs_get_vfs_options:
1116 * @fs: fstab/mtab entry pointer
1117 *
1118 * Returns: pointer to fs-independent (VFS) mount option string or NULL.
1119 */
1120const char *mnt_fs_get_vfs_options(struct libmnt_fs *fs)
1121{
1122 if (!fs)
1123 return NULL;
1124 if (fs->optlist)
1125 sync_opts_from_optlist(fs, fs->optlist);
1126#ifdef HAVE_STATMOUNT_API
1127 else
1128 mnt_fs_try_statmount(fs, vfs_optstr, STATMOUNT_MNT_BASIC);
1129#endif
1130 return fs->vfs_optstr;
1131}
1132
1133/**
1134 * mnt_fs_get_vfs_options_all:
1135 * @fs: fstab/mtab entry pointer
1136 *
1137 * Returns: pointer to newlly allocated string (can be freed by free(3)) or
1138 * NULL in case of error. The string contains all (including defaults) mount
1139 * options.
1140 */
1141char *mnt_fs_get_vfs_options_all(struct libmnt_fs *fs)
1142{
1143 const struct libmnt_optmap *map = mnt_get_builtin_optmap(MNT_LINUX_MAP);
1144 const struct libmnt_optmap *ent;
1145 const char *opts = mnt_fs_get_options(fs);
1146 char *result = NULL;
1147 unsigned long flags = 0;
1148
1149 if (!opts || mnt_optstr_get_flags(opts, &flags, map))
1150 return NULL;
1151
1152 for (ent = map ; ent && ent->name ; ent++){
1153 if (ent->id & flags) { /* non-default value */
1154 if (!(ent->mask & MNT_INVERT))
1155 mnt_optstr_append_option(&result, ent->name, NULL);
1156 else
1157 continue;
1158 } else if (ent->mask & MNT_INVERT)
1159 mnt_optstr_append_option(&result, ent->name, NULL);
1160 }
1161
1162 return result;
1163}
1164
1165/**
1166 * mnt_fs_get_user_options:
1167 * @fs: fstab/mtab entry pointer
1168 *
1169 * Returns: pointer to userspace mount option string or NULL.
1170 */
1171const char *mnt_fs_get_user_options(struct libmnt_fs *fs)
1172{
1173 if (!fs)
1174 return NULL;
1175 if (fs->optlist)
1176 sync_opts_from_optlist(fs, fs->optlist);
1177
1178 return fs->user_optstr;
1179}
1180
1181/**
1182 * mnt_fs_get_attributes:
1183 * @fs: fstab/mtab entry pointer
1184 *
1185 * Returns: pointer to attributes string or NULL.
1186 */
1187const char *mnt_fs_get_attributes(struct libmnt_fs *fs)
1188{
1189 return fs ? fs->attrs : NULL;
1190}
1191
1192/**
1193 * mnt_fs_set_attributes:
1194 * @fs: fstab/mtab/mountinfo entry
1195 * @optstr: options string
1196 *
1197 * Sets mount attributes. The attributes are mount(2) and mount(8) independent
1198 * options, these options are not sent to the kernel and are not interpreted by
1199 * libmount. The attributes are stored in /run/mount/utab only.
1200 *
1201 * The attributes are managed by libmount in userspace only. It's possible
1202 * that information stored in userspace will not be available for libmount
1203 * after CLONE_FS unshare. Be careful, and don't use attributes if possible.
1204 *
1205 * Please note that the new mount kernel API calls some VFS flags "mount attributes"
1206 * (MOUNT_ATTR_*), but these flags are not related to the old libmount functionality.
1207 *
1208 * Returns: 0 on success or negative number in case of error.
1209 */
1210int mnt_fs_set_attributes(struct libmnt_fs *fs, const char *optstr)
1211{
1212 return strdup_to_struct_member(fs, attrs, optstr);
1213}
1214
1215/**
1216 * mnt_fs_append_attributes
1217 * @fs: fstab/mtab/mountinfo entry
1218 * @optstr: options string
1219 *
1220 * Appends mount attributes. (See mnt_fs_set_attributes()).
1221 *
1222 * Returns: 0 on success or negative number in case of error.
1223 */
1224int mnt_fs_append_attributes(struct libmnt_fs *fs, const char *optstr)
1225{
1226 if (!fs)
1227 return -EINVAL;
1228 if (!optstr)
1229 return 0;
1230 return mnt_optstr_append_option(&fs->attrs, optstr, NULL);
1231}
1232
1233/**
1234 * mnt_fs_prepend_attributes
1235 * @fs: fstab/mtab/mountinfo entry
1236 * @optstr: options string
1237 *
1238 * Prepends mount attributes. (See mnt_fs_set_attributes()).
1239 *
1240 * Returns: 0 on success or negative number in case of error.
1241 */
1242int mnt_fs_prepend_attributes(struct libmnt_fs *fs, const char *optstr)
1243{
1244 if (!fs)
1245 return -EINVAL;
1246 if (!optstr)
1247 return 0;
1248 return mnt_optstr_prepend_option(&fs->attrs, optstr, NULL);
1249}
1250
1251
1252/**
1253 * mnt_fs_get_freq:
1254 * @fs: fstab/mtab/mountinfo entry pointer
1255 *
1256 * Returns: dump frequency in days.
1257 */
1258int mnt_fs_get_freq(struct libmnt_fs *fs)
1259{
1260 return fs ? fs->freq : 0;
1261}
1262
1263/**
1264 * mnt_fs_set_freq:
1265 * @fs: fstab/mtab entry pointer
1266 * @freq: dump frequency in days
1267 *
1268 * Returns: 0 on success or negative number in case of error.
1269 */
1270int mnt_fs_set_freq(struct libmnt_fs *fs, int freq)
1271{
1272 if (!fs)
1273 return -EINVAL;
1274 fs->freq = freq;
1275 return 0;
1276}
1277
1278/**
1279 * mnt_fs_get_passno:
1280 * @fs: fstab/mtab entry pointer
1281 *
1282 * Returns: "pass number on parallel fsck".
1283 */
1284int mnt_fs_get_passno(struct libmnt_fs *fs)
1285{
1286 return fs ? fs->passno: 0;
1287}
1288
1289/**
1290 * mnt_fs_set_passno:
1291 * @fs: fstab/mtab entry pointer
1292 * @passno: pass number
1293 *
1294 * Returns: 0 on success or negative number in case of error.
1295 */
1296int mnt_fs_set_passno(struct libmnt_fs *fs, int passno)
1297{
1298 if (!fs)
1299 return -EINVAL;
1300 fs->passno = passno;
1301 return 0;
1302}
1303
1304/**
1305 * mnt_fs_get_root:
1306 * @fs: /proc/self/mountinfo entry
1307 *
1308 * Returns: root of the mount within the filesystem or NULL
1309 */
1310const char *mnt_fs_get_root(struct libmnt_fs *fs)
1311{
1312 if (!fs)
1313 return NULL;
1314#ifdef HAVE_STATMOUNT_API
1315 mnt_fs_try_statmount(fs, root, STATMOUNT_MNT_ROOT);
1316#endif
1317 return fs->root;
1318}
1319
1320/**
1321 * mnt_fs_set_root:
1322 * @fs: mountinfo entry
1323 * @path: root path
1324 *
1325 * Returns: 0 on success or negative number in case of error.
1326 */
1327int mnt_fs_set_root(struct libmnt_fs *fs, const char *path)
1328{
1329 return strdup_to_struct_member(fs, root, path);
1330}
1331
1332/**
1333 * mnt_fs_get_swaptype:
1334 * @fs: /proc/swaps entry
1335 *
1336 * Returns: swap type or NULL
1337 */
1338const char *mnt_fs_get_swaptype(struct libmnt_fs *fs)
1339{
1340 return fs ? fs->swaptype : NULL;
1341}
1342
1343/**
1344 * mnt_fs_get_size:
1345 * @fs: /proc/swaps entry
1346 *
1347 * Returns: size
1348 */
1349off_t mnt_fs_get_size(struct libmnt_fs *fs)
1350{
1351 return fs ? fs->size : 0;
1352}
1353
1354/**
1355 * mnt_fs_get_usedsize:
1356 * @fs: /proc/swaps entry
1357 *
1358 * Returns: used size
1359 */
1360off_t mnt_fs_get_usedsize(struct libmnt_fs *fs)
1361{
1362 return fs ? fs->usedsize : 0;
1363}
1364
1365/**
1366 * mnt_fs_get_priority:
1367 * @fs: /proc/swaps entry
1368 *
1369 * Returns: priority
1370 */
1371int mnt_fs_get_priority(struct libmnt_fs *fs)
1372{
1373 return fs ? fs->priority : 0;
1374}
1375
1376/**
1377 * mnt_fs_set_priority:
1378 * @fs: /proc/swaps entry
1379 * @prio: priority
1380 *
1381 * Since: 2.28
1382 *
1383 * Returns: 0 or -1 in case of error
1384 */
1385int mnt_fs_set_priority(struct libmnt_fs *fs, int prio)
1386{
1387 if (!fs)
1388 return -EINVAL;
1389 fs->priority = prio;
1390 return 0;
1391}
1392
1393/**
1394 * mnt_fs_get_bindsrc:
1395 * @fs: /run/mount/utab entry
1396 *
1397 * Returns: full path that was used for mount(2) on MS_BIND
1398 */
1399const char *mnt_fs_get_bindsrc(struct libmnt_fs *fs)
1400{
1401 return fs ? fs->bindsrc : NULL;
1402}
1403
1404/**
1405 * mnt_fs_set_bindsrc:
1406 * @fs: filesystem
1407 * @src: path
1408 *
1409 * Returns: 0 on success or negative number in case of error.
1410 */
1411int mnt_fs_set_bindsrc(struct libmnt_fs *fs, const char *src)
1412{
1413 return strdup_to_struct_member(fs, bindsrc, src);
1414}
1415
1416/**
1417 * mnt_fs_get_id:
1418 * @fs: /proc/self/mountinfo entry
1419 *
1420 * This ID is "old" and used in mountinfo only. Since Linux v6.8 there is also unique
1421 * 64-bit ID, see mnt_fs_get_uniq_id().
1422 *
1423 * Returns: mount ID or negative number in case of error.
1424 */
1425int mnt_fs_get_id(struct libmnt_fs *fs)
1426{
1427 if (!fs)
1428 return 0;
1429#ifdef HAVE_STATMOUNT_API
1430 mnt_fs_try_statmount(fs, id, STATMOUNT_MNT_BASIC);
1431#endif
1432 return fs->id;
1433}
1434
1435/**
1436 * mnt_fs_get_uniq_id:
1437 * @fs: filesystem instance
1438 *
1439 * This ID is provided by statmount() or statx(STATX_MNT_ID_UNIQUE) since Linux
1440 * kernel since v6.8.
1441 *
1442 * Returns: unique mount ID
1443 *
1444 * Since: 2.41
1445 */
1446uint64_t mnt_fs_get_uniq_id(struct libmnt_fs *fs)
1447{
1448 if (!fs)
1449 return 0;
1450#ifdef HAVE_STATMOUNT_API
1451 mnt_fs_try_statmount(fs, uniq_id, STATMOUNT_MNT_BASIC);
1452#endif
1453 return fs->uniq_id;
1454}
1455
1456/**
1457 * mnt_fs_set_uniq_id:
1458 * @fs: filesystem instance
1459 * @id: mount node ID
1460 *
1461 * This ID is provided by statmount() or statx(STATX_MNT_ID_UNIQUE) since Linux
1462 * kernel since v6.8.
1463 *
1464 * Returns: 0 or negative number in case of error.
1465 *
1466 * Since: 2.41
1467 */
1468int mnt_fs_set_uniq_id(struct libmnt_fs *fs, uint64_t id)
1469{
1470 if (!fs)
1471 return -EINVAL;
1472 fs->uniq_id = id;
1473 return 0;
1474}
1475
1476/**
1477 * mnt_fs_get_parent_id:
1478 * @fs: /proc/self/mountinfo entry
1479 *
1480 * Returns: parent mount ID or negative number in case of error.
1481 */
1482int mnt_fs_get_parent_id(struct libmnt_fs *fs)
1483{
1484 if (!fs)
1485 return 0;
1486#ifdef HAVE_STATMOUNT_API
1487 mnt_fs_try_statmount(fs, parent, STATMOUNT_MNT_BASIC);
1488#endif
1489 return fs->parent;
1490}
1491
1492/**
1493 * mnt_fs_get_parent_uniq_id:
1494 * @fs: filesystem instance
1495 *
1496 * This ID is provided by statmount() since Linux kernel since v6.8.
1497 *
1498 * Returns: parent mount ID or 0 if not avalable
1499 */
1500uint64_t mnt_fs_get_parent_uniq_id(struct libmnt_fs *fs)
1501{
1502 if (!fs)
1503 return 0;
1504#ifdef HAVE_STATMOUNT_API
1505 mnt_fs_try_statmount(fs, uniq_parent, STATMOUNT_MNT_BASIC);
1506#endif
1507 return fs->uniq_parent;
1508}
1509
1510/**
1511 * mnt_fs_get_ns:
1512 * @fs: filesystem instance
1513 *
1514 * This ID is provided by statmount() since Linux kernel since v6.10
1515 *
1516 * Returns: parent namespace ID or 0 if not avalable.
1517 *
1518 * Since: 2.41
1519 */
1520uint64_t mnt_fs_get_ns(struct libmnt_fs *fs)
1521{
1522 if (!fs)
1523 return 0;
1524#ifdef HAVE_STATMOUNT_API
1525 mnt_fs_try_statmount(fs, ns_id, STATMOUNT_MNT_NS_ID);
1526#endif
1527 return fs->ns_id;
1528}
1529
1530/**
1531 * mnt_fs_set_ns:
1532 * @fs: filesystem instance
1533 * @id: namespace ID (or 0)
1534 *
1535 * Returns: 0 or <0 in case of error.
1536 *
1537 * Sinse: 2.41
1538 */
1539int mnt_fs_set_ns(struct libmnt_fs *fs, uint64_t id)
1540{
1541 if (!fs)
1542 return -EINVAL;
1543 fs->ns_id = id;
1544 return 0;
1545}
1546
1547
1548/**
1549 * mnt_fs_get_devno:
1550 * @fs: /proc/self/mountinfo entry
1551 *
1552 * Returns: value of st_dev for files on filesystem or 0 in case of error.
1553 */
1554dev_t mnt_fs_get_devno(struct libmnt_fs *fs)
1555{
1556 if (!fs)
1557 return 0;
1558#ifdef HAVE_STATMOUNT_API
1559 mnt_fs_try_statmount(fs, devno, STATMOUNT_SB_BASIC);
1560#endif
1561 return fs->devno;
1562}
1563
1564/**
1565 * mnt_fs_get_tid:
1566 * @fs: /proc/tid/mountinfo entry
1567 *
1568 * Returns: TID (task ID) for filesystems read from the mountinfo file
1569 */
1570pid_t mnt_fs_get_tid(struct libmnt_fs *fs)
1571{
1572 return fs ? fs->tid : 0;
1573}
1574
1575/**
1576 * mnt_fs_get_option:
1577 * @fs: fstab/mtab/mountinfo entry pointer
1578 * @name: option name
1579 * @value: returns pointer to the beginning of the value (e.g. name=VALUE) or NULL
1580 * @valsz: returns size of options value or 0
1581 *
1582 * Returns: 0 on success, 1 when @name not found or negative number in case of error.
1583 */
1584int mnt_fs_get_option(struct libmnt_fs *fs, const char *name,
1585 char **value, size_t *valsz)
1586{
1587 char rc = 1;
1588
1589 if (!fs)
1590 return -EINVAL;
1591
1592 if (fs->optlist)
1593 sync_opts_from_optlist(fs, fs->optlist);
1594#ifdef HAVE_STATMOUNT_API
1595 else
1596 mnt_fs_try_statmount(fs, vfs_optstr, STATMOUNT_SB_BASIC | STATMOUNT_MNT_BASIC);
1597#endif
1598 if (fs->fs_optstr)
1599 rc = mnt_optstr_get_option(fs->fs_optstr, name, value, valsz);
1600 if (rc == 1 && fs->vfs_optstr)
1601 rc = mnt_optstr_get_option(fs->vfs_optstr, name, value, valsz);
1602 if (rc == 1 && fs->user_optstr)
1603 rc = mnt_optstr_get_option(fs->user_optstr, name, value, valsz);
1604 return rc;
1605}
1606
1607/**
1608 * mnt_fs_get_attribute:
1609 * @fs: fstab/mtab/mountinfo entry pointer
1610 * @name: option name
1611 * @value: returns pointer to the beginning of the value (e.g. name=VALUE) or NULL
1612 * @valsz: returns size of options value or 0
1613 *
1614 * Returns: 0 on success, 1 when @name not found or negative number in case of error.
1615 */
1616int mnt_fs_get_attribute(struct libmnt_fs *fs, const char *name,
1617 char **value, size_t *valsz)
1618{
1619 char rc = 1;
1620
1621 if (!fs)
1622 return -EINVAL;
1623 if (fs->attrs)
1624 rc = mnt_optstr_get_option(fs->attrs, name, value, valsz);
1625 return rc;
1626}
1627
1628/**
1629 * mnt_fs_get_comment:
1630 * @fs: fstab/mtab/mountinfo entry pointer
1631 *
1632 * Returns: comment string
1633 */
1634const char *mnt_fs_get_comment(struct libmnt_fs *fs)
1635{
1636 if (!fs)
1637 return NULL;
1638 return fs->comment;
1639}
1640
1641/**
1642 * mnt_fs_set_comment:
1643 * @fs: fstab entry pointer
1644 * @comm: comment string
1645 *
1646 * Note that the comment has to be terminated by '\n' (new line), otherwise
1647 * the whole filesystem entry will be written as a comment to the tabfile (e.g.
1648 * fstab).
1649 *
1650 * Returns: 0 on success or <0 in case of error.
1651 */
1652int mnt_fs_set_comment(struct libmnt_fs *fs, const char *comm)
1653{
1654 return strdup_to_struct_member(fs, comment, comm);
1655}
1656
1657/**
1658 * mnt_fs_append_comment:
1659 * @fs: fstab entry pointer
1660 * @comm: comment string
1661 *
1662 * See also mnt_fs_set_comment().
1663 *
1664 * Returns: 0 on success or <0 in case of error.
1665 */
1666int mnt_fs_append_comment(struct libmnt_fs *fs, const char *comm)
1667{
1668 if (!fs)
1669 return -EINVAL;
1670
1671 return ul_strappend(&fs->comment, comm);
1672}
1673
1674/**
1675 * mnt_fs_match_target:
1676 * @fs: filesystem
1677 * @target: mountpoint path
1678 * @cache: tags/paths cache or NULL
1679 *
1680 * Possible are three attempts:
1681 * 1) compare @target with @fs->target
1682 *
1683 * 2) realpath(@target) with @fs->target
1684 *
1685 * 3) realpath(@target) with realpath(@fs->target) if @fs is not from
1686 * /proc/self/mountinfo.
1687 *
1688 * However, if mnt_cache_set_targets(cache, mtab) was called, and the
1689 * path @target or @fs->target is found in the @mtab, the canonicalization is
1690 * is not performed (see mnt_resolve_target()).
1691 *
1692 * The 2nd and 3rd attempts are not performed when @cache is NULL.
1693 *
1694 * Returns: 1 if @fs target is equal to @target, else 0.
1695 */
1696int mnt_fs_match_target(struct libmnt_fs *fs, const char *target,
1697 struct libmnt_cache *cache)
1698{
1699 int rc = 0;
1700
1701 if (!fs || !target)
1702 return 0;
1703#ifdef HAVE_STATMOUNT_API
1704 mnt_fs_try_statmount(fs, target, STATMOUNT_MNT_POINT);
1705#endif
1706 if (!fs->target)
1707 return 0;
1708
1709 /* 1) native paths */
1710 rc = mnt_fs_streq_target(fs, target);
1711
1712 if (!rc && cache) {
1713 /* 2) - canonicalized and non-canonicalized */
1714 char *cn = mnt_resolve_target(target, cache);
1715 rc = (cn && mnt_fs_streq_target(fs, cn));
1716
1717 /* 3) - canonicalized and canonicalized */
1718 if (!rc && cn && !mnt_fs_is_kernel(fs) && !mnt_fs_is_swaparea(fs)) {
1719 char *tcn = mnt_resolve_target(fs->target, cache);
1720 rc = (tcn && strcmp(cn, tcn) == 0);
1721 }
1722 }
1723
1724 return rc;
1725}
1726
1727/**
1728 * mnt_fs_match_source:
1729 * @fs: filesystem
1730 * @source: tag or path (device or so) or NULL
1731 * @cache: tags/paths cache or NULL
1732 *
1733 * Four attempts are possible:
1734 * 1) compare @source with @fs->source
1735 * 2) compare realpath(@source) with @fs->source
1736 * 3) compare realpath(@source) with realpath(@fs->source)
1737 * 4) compare realpath(@source) with evaluated tag from @fs->source
1738 *
1739 * The 2nd, 3rd and 4th attempts are not performed when @cache is NULL. The
1740 * 2nd and 3rd attempts are not performed if @fs->source is tag.
1741 *
1742 * Returns: 1 if @fs source is equal to @source, else 0.
1743 */
1744int mnt_fs_match_source(struct libmnt_fs *fs, const char *source,
1745 struct libmnt_cache *cache)
1746{
1747 char *cn;
1748 const char *src, *t, *v;
1749
1750 if (!fs)
1751 return 0;
1752
1753 /* 1) native paths... */
1754 if (mnt_fs_streq_srcpath(fs, source) == 1)
1755 return 1;
1756
1757 if (!source || !fs->source)
1758 return 0;
1759
1760 /* ... and tags */
1761 if (fs->tagname && strcmp(source, fs->source) == 0)
1762 return 1;
1763
1764 if (!cache)
1765 return 0;
1766 if (fs->flags & (MNT_FS_NET | MNT_FS_PSEUDO))
1767 return 0;
1768
1769 cn = mnt_resolve_spec(source, cache);
1770 if (!cn)
1771 return 0;
1772
1773 /* 2) canonicalized and native */
1774 src = mnt_fs_get_srcpath(fs);
1775 if (src && mnt_fs_streq_srcpath(fs, cn))
1776 return 1;
1777
1778 /* 3) canonicalized and canonicalized */
1779 if (src) {
1780 src = mnt_resolve_path(src, cache);
1781 if (src && !strcmp(cn, src))
1782 return 1;
1783 }
1784 if (src || mnt_fs_get_tag(fs, &t, &v))
1785 /* src path does not match and the tag is not defined */
1786 return 0;
1787
1788 /* read @source's tags to the cache */
1789 if (mnt_cache_read_tags(cache, cn) < 0) {
1790 if (errno == EACCES) {
1791 /* we don't have permissions to read TAGs from
1792 * @source, but can translate the @fs tag to devname.
1793 *
1794 * (because libblkid uses udev symlinks and this is
1795 * accessible for non-root uses)
1796 */
1797 char *x = mnt_resolve_tag(t, v, cache);
1798 if (x && !strcmp(x, cn))
1799 return 1;
1800 }
1801 return 0;
1802 }
1803
1804 /* 4) has the @source a tag that matches with the tag from @fs ? */
1805 if (mnt_cache_device_has_tag(cache, cn, t, v))
1806 return 1;
1807
1808 return 0;
1809}
1810
1811/**
1812 * mnt_fs_match_fstype:
1813 * @fs: filesystem
1814 * @types: filesystem name or comma delimited list of filesystems
1815 *
1816 * For more details see mnt_match_fstype().
1817 *
1818 * Returns: 1 if @fs type is matching to @types, else 0. The function returns
1819 * 0 when types is NULL.
1820 */
1821int mnt_fs_match_fstype(struct libmnt_fs *fs, const char *types)
1822{
1823 return mnt_match_fstype(mnt_fs_get_fstype(fs), types);
1824}
1825
1826/**
1827 * mnt_fs_match_options:
1828 * @fs: filesystem
1829 * @options: comma delimited list of options (and nooptions)
1830 *
1831 * For more details see mnt_match_options().
1832 *
1833 * Returns: 1 if @fs type is matching to @options, else 0. The function returns
1834 * 0 when types is NULL.
1835 */
1836int mnt_fs_match_options(struct libmnt_fs *fs, const char *options)
1837{
1838 return mnt_match_options(mnt_fs_get_options(fs), options);
1839}
1840
1841/**
1842 * mnt_fs_print_debug
1843 * @fs: fstab/mtab/mountinfo entry
1844 * @file: file stream
1845 *
1846 * Returns: 0 on success or negative number in case of error.
1847 */
1848int mnt_fs_print_debug(struct libmnt_fs *fs, FILE *file)
1849{
1850 unsigned long pro = 0;
1851 int stmnt_disabled = 1;
1852
1853 if (!fs || !file)
1854 return -EINVAL;
1855
1856 if (fs->optlist)
1857 sync_opts_from_optlist(fs, fs->optlist);
1858
1859 if (fs->stmnt)
1860 stmnt_disabled = mnt_statmnt_disable_fetching(fs->stmnt, 1);
1861
1862 fprintf(file, "------ fs:\n");
1863 if (mnt_fs_get_source(fs))
1864 fprintf(file, "source: %s\n", mnt_fs_get_source(fs));
1865 if (mnt_fs_get_target(fs))
1866 fprintf(file, "target: %s\n", mnt_fs_get_target(fs));
1867 if (mnt_fs_get_fstype(fs))
1868 fprintf(file, "fstype: %s\n", mnt_fs_get_fstype(fs));
1869
1870 if (mnt_fs_get_options(fs))
1871 fprintf(file, "optstr: %s\n", mnt_fs_get_options(fs));
1872 if (mnt_fs_get_vfs_options(fs))
1873 fprintf(file, "VFS-optstr: %s\n", mnt_fs_get_vfs_options(fs));
1874 if (mnt_fs_get_fs_options(fs))
1875 fprintf(file, "FS-opstr: %s\n", mnt_fs_get_fs_options(fs));
1876 if (mnt_fs_get_user_options(fs))
1877 fprintf(file, "user-optstr: %s\n", mnt_fs_get_user_options(fs));
1878 if (mnt_fs_get_optional_fields(fs))
1879 fprintf(file, "optional-fields: '%s'\n", mnt_fs_get_optional_fields(fs));
1880 if (mnt_fs_get_attributes(fs))
1881 fprintf(file, "attributes: %s\n", mnt_fs_get_attributes(fs));
1882
1883 if (mnt_fs_get_propagation(fs, &pro) == 0 && pro)
1884 fprintf(file, "propagation: %s %s %s\n",
1885 pro & MS_SHARED ? "shared" : "private",
1886 pro & MS_SLAVE ? "slave" : "",
1887 pro & MS_UNBINDABLE ? "unbindable" : "");
1888
1889 if (mnt_fs_get_root(fs))
1890 fprintf(file, "root: %s\n", mnt_fs_get_root(fs));
1891
1892 if (mnt_fs_get_swaptype(fs))
1893 fprintf(file, "swaptype: %s\n", mnt_fs_get_swaptype(fs));
1894 if (mnt_fs_get_size(fs))
1895 fprintf(file, "size: %jd\n", mnt_fs_get_size(fs));
1896 if (mnt_fs_get_usedsize(fs))
1897 fprintf(file, "usedsize: %jd\n", mnt_fs_get_usedsize(fs));
1898 if (mnt_fs_get_priority(fs))
1899 fprintf(file, "priority: %d\n", mnt_fs_get_priority(fs));
1900
1901 if (mnt_fs_get_bindsrc(fs))
1902 fprintf(file, "bindsrc: %s\n", mnt_fs_get_bindsrc(fs));
1903 if (mnt_fs_get_freq(fs))
1904 fprintf(file, "freq: %d\n", mnt_fs_get_freq(fs));
1905 if (mnt_fs_get_passno(fs))
1906 fprintf(file, "pass: %d\n", mnt_fs_get_passno(fs));
1907 if (mnt_fs_get_id(fs))
1908 fprintf(file, "id: %d\n", mnt_fs_get_id(fs));
1909 if (mnt_fs_get_parent_id(fs))
1910 fprintf(file, "parent: %d\n", mnt_fs_get_parent_id(fs));
1911 if (mnt_fs_get_uniq_id(fs))
1912 fprintf(file, "uniq-id: %" PRIu64 "\n", mnt_fs_get_uniq_id(fs));
1913 if (mnt_fs_get_parent_uniq_id(fs))
1914 fprintf(file, "uniq-parent: %" PRIu64 "\n", mnt_fs_get_parent_uniq_id(fs));
1915
1916 if (mnt_fs_get_devno(fs))
1917 fprintf(file, "devno: %d:%d\n", major(mnt_fs_get_devno(fs)),
1918 minor(mnt_fs_get_devno(fs)));
1919 if (mnt_fs_get_tid(fs))
1920 fprintf(file, "tid: %d\n", mnt_fs_get_tid(fs));
1921 if (mnt_fs_get_comment(fs))
1922 fprintf(file, "comment: '%s'\n", mnt_fs_get_comment(fs));
1923
1924 if (fs->stmnt)
1925 mnt_statmnt_disable_fetching(fs->stmnt, stmnt_disabled);
1926 return 0;
1927}
1928
1929/**
1930 * mnt_free_mntent:
1931 * @mnt: mount entry
1932 *
1933 * Deallocates the "mntent.h" mount entry.
1934 */
1935void mnt_free_mntent(struct mntent *mnt)
1936{
1937 if (mnt) {
1938 free(mnt->mnt_fsname);
1939 free(mnt->mnt_dir);
1940 free(mnt->mnt_type);
1941 free(mnt->mnt_opts);
1942 free(mnt);
1943 }
1944}
1945
1946/**
1947 * mnt_fs_to_mntent:
1948 * @fs: filesystem
1949 * @mnt: mount description (as described in mntent.h)
1950 *
1951 * Copies the information from @fs to struct mntent @mnt. If @mnt is already set,
1952 * then the struct mntent items are reallocated and updated. See also
1953 * mnt_free_mntent().
1954 *
1955 * Returns: 0 on success and a negative number in case of error.
1956 */
1957int mnt_fs_to_mntent(struct libmnt_fs *fs, struct mntent **mnt)
1958{
1959 int rc;
1960 struct mntent *m;
1961
1962 if (!fs || !mnt)
1963 return -EINVAL;
1964
1965 m = *mnt;
1966 if (!m) {
1967 m = calloc(1, sizeof(*m));
1968 if (!m)
1969 return -ENOMEM;
1970 }
1971
1972 if ((rc = update_str(&m->mnt_fsname, mnt_fs_get_source(fs))))
1973 goto err;
1974 if ((rc = update_str(&m->mnt_dir, mnt_fs_get_target(fs))))
1975 goto err;
1976 if ((rc = update_str(&m->mnt_type, mnt_fs_get_fstype(fs))))
1977 goto err;
1978
1979 errno = 0;
1980 m->mnt_opts = mnt_fs_strdup_options(fs);
1981 if (!m->mnt_opts && errno) {
1982 rc = -errno;
1983 goto err;
1984 }
1985
1986 m->mnt_freq = mnt_fs_get_freq(fs);
1987 m->mnt_passno = mnt_fs_get_passno(fs);
1988
1989 if (!m->mnt_fsname) {
1990 m->mnt_fsname = strdup("none");
1991 if (!m->mnt_fsname)
1992 goto err;
1993 }
1994 *mnt = m;
1995
1996 return 0;
1997err:
1998 if (m != *mnt)
1999 mnt_free_mntent(m);
2000 return rc;
2001}