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