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