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