1 /*
2  * Copyright (C) 2010,2011,2012 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: context
10  * @title: Library high-level context
11  * @short_description: high-level API to mount/umount devices.
12  *
13  * <informalexample>
14  *   <programlisting>
15  *	struct libmnt_context *cxt = mnt_new_context();
16  *
17  *	mnt_context_set_options(cxt, "aaa,bbb,ccc=CCC");
18  *	mnt_context_set_mflags(cxt, MS_NOATIME|MS_NOEXEC);
19  *	mnt_context_set_target(cxt, "/mnt/foo");
20  *
21  *	if (!mnt_context_mount(cxt))
22  *		printf("successfully mounted\n");
23  *	mnt_free_context(cxt);
24  *
25  *   </programlisting>
26  * </informalexample>
27  *
28  * This code is similar to:
29  *
30  *   mount -o aaa,bbb,ccc=CCC,noatime,noexec /mnt/foo
31  *
32  */
33 
34 #include "mountP.h"
35 #include "fileutils.h"
36 
37 #include <sys/wait.h>
38 
39 /**
40  * mnt_new_context:
41  *
42  * Returns: newly allocated mount context
43  */
mnt_new_context(void)44 struct libmnt_context *mnt_new_context(void)
45 {
46 	struct libmnt_context *cxt;
47 	uid_t ruid, euid;
48 
49 	cxt = calloc(1, sizeof(*cxt));
50 	if (!cxt)
51 		return NULL;
52 
53 	INIT_LIST_HEAD(&cxt->addmounts);
54 
55 	ruid = getuid();
56 	euid = geteuid();
57 
58 	mnt_context_reset_status(cxt);
59 
60 	cxt->loopdev_fd = -1;
61 
62 	/* if we're really root and aren't running setuid */
63 	cxt->restricted = (uid_t) 0 == ruid && ruid == euid ? 0 : 1;
64 
65 	DBG(CXT, ul_debugobj(cxt, "----> allocate %s",
66 				cxt->restricted ? "[RESTRICTED]" : ""));
67 
68 
69 	return cxt;
70 }
71 
72 /**
73  * mnt_free_context:
74  * @cxt: mount context
75  *
76  * Deallocates context struct.
77  */
mnt_free_context(struct libmnt_context * cxt)78 void mnt_free_context(struct libmnt_context *cxt)
79 {
80 	if (!cxt)
81 		return;
82 
83 	mnt_reset_context(cxt);
84 
85 	free(cxt->fstype_pattern);
86 	free(cxt->optstr_pattern);
87 
88 	mnt_unref_table(cxt->fstab);
89 	mnt_unref_cache(cxt->cache);
90 
91 	mnt_context_clear_loopdev(cxt);
92 	mnt_free_lock(cxt->lock);
93 	mnt_free_update(cxt->update);
94 
95 	free(cxt->children);
96 
97 	DBG(CXT, ul_debugobj(cxt, "<---- free"));
98 	free(cxt);
99 }
100 
101 /**
102  * mnt_reset_context:
103  * @cxt: mount context
104  *
105  * Resets all information in the context that is directly related to
106  * the latest mount (spec, source, target, mount options, ...).
107  *
108  * The match patterns, cached fstab, cached canonicalized paths and tags and
109  * [e]uid are not reset. You have to use
110  *
111  *	mnt_context_set_fstab(cxt, NULL);
112  *	mnt_context_set_cache(cxt, NULL);
113  *	mnt_context_set_fstype_pattern(cxt, NULL);
114  *	mnt_context_set_options_pattern(cxt, NULL);
115  *
116  *
117  * to reset this stuff.
118  *
119  * Returns: 0 on success, negative number in case of error.
120  */
mnt_reset_context(struct libmnt_context * cxt)121 int mnt_reset_context(struct libmnt_context *cxt)
122 {
123 	int fl;
124 
125 	if (!cxt)
126 		return -EINVAL;
127 
128 	DBG(CXT, ul_debugobj(cxt, "<---- reset [status=%d] ---->",
129 				mnt_context_get_status(cxt)));
130 
131 	fl = cxt->flags;
132 
133 	mnt_unref_fs(cxt->fs);
134 	mnt_unref_table(cxt->mtab);
135 	mnt_unref_table(cxt->utab);
136 
137 	free(cxt->helper);
138 	free(cxt->orig_user);
139 
140 	cxt->fs = NULL;
141 	cxt->mtab = NULL;
142 	cxt->utab = NULL;
143 	cxt->helper = NULL;
144 	cxt->orig_user = NULL;
145 	cxt->mountflags = 0;
146 	cxt->user_mountflags = 0;
147 	cxt->mountdata = NULL;
148 	cxt->flags = MNT_FL_DEFAULT;
149 
150 	/* free additional mounts list */
151 	while (!list_empty(&cxt->addmounts)) {
152 		struct libmnt_addmount *ad = list_entry(cxt->addmounts.next,
153 				                  struct libmnt_addmount,
154 						  mounts);
155 		mnt_free_addmount(ad);
156 	}
157 
158 	mnt_context_reset_status(cxt);
159 
160 	if (cxt->table_fltrcb)
161 		mnt_context_set_tabfilter(cxt, NULL, NULL);
162 
163 	/* restore non-resettable flags */
164 	cxt->flags |= (fl & MNT_FL_NOMTAB);
165 	cxt->flags |= (fl & MNT_FL_FAKE);
166 	cxt->flags |= (fl & MNT_FL_SLOPPY);
167 	cxt->flags |= (fl & MNT_FL_VERBOSE);
168 	cxt->flags |= (fl & MNT_FL_NOHELPERS);
169 	cxt->flags |= (fl & MNT_FL_LOOPDEL);
170 	cxt->flags |= (fl & MNT_FL_LAZY);
171 	cxt->flags |= (fl & MNT_FL_FORK);
172 	cxt->flags |= (fl & MNT_FL_FORCE);
173 	cxt->flags |= (fl & MNT_FL_NOCANONICALIZE);
174 	cxt->flags |= (fl & MNT_FL_RDONLY_UMOUNT);
175 	cxt->flags |= (fl & MNT_FL_NOSWAPMATCH);
176 	cxt->flags |= (fl & MNT_FL_TABPATHS_CHECKED);
177 	return 0;
178 }
179 
180 /**
181  * mnt_context_reset_status:
182  * @cxt: context
183  *
184  * Resets mount(2) and mount.type statuses, so mnt_context_do_mount() or
185  * mnt_context_do_umount() could be again called with the same settings.
186  *
187  * BE CAREFUL -- after this soft reset the libmount will NOT parse mount
188  * options, evaluate permissions or apply stuff from fstab.
189  *
190  * Returns: 0 on success, negative number in case of error.
191  */
mnt_context_reset_status(struct libmnt_context * cxt)192 int mnt_context_reset_status(struct libmnt_context *cxt)
193 {
194 	assert(cxt);
195 	if (!cxt)
196 		return -EINVAL;
197 
198 	cxt->syscall_status = 1;		/* means not called yet */
199 	cxt->helper_exec_status = 1;
200 	cxt->helper_status = 0;
201 	return 0;
202 }
203 
context_init_paths(struct libmnt_context * cxt,int writable)204 static int context_init_paths(struct libmnt_context *cxt, int writable)
205 {
206 	assert(cxt);
207 
208 	if (!cxt->mtab_path)
209 		cxt->mtab_path = mnt_get_mtab_path();
210 	if (!cxt->utab_path)
211 		cxt->utab_path = mnt_get_utab_path();
212 
213 	if (!writable)
214 		return 0;		/* only paths wanted */
215 	if (mnt_context_is_nomtab(cxt))
216 		return 0;		/* write mode overrided by mount -n */
217 	if (cxt->flags & MNT_FL_TABPATHS_CHECKED)
218 		return 0;
219 
220 	DBG(CXT, ul_debugobj(cxt, "checking for writable tab files"));
221 
222 	mnt_has_regular_mtab(&cxt->mtab_path, &cxt->mtab_writable);
223 
224 	if (!cxt->mtab_writable)
225 		/* use /run/mount/utab if /etc/mtab is useless */
226 		mnt_has_regular_utab(&cxt->utab_path, &cxt->utab_writable);
227 
228 	cxt->flags |= MNT_FL_TABPATHS_CHECKED;
229 	return 0;
230 }
231 
mnt_context_mtab_writable(struct libmnt_context * cxt)232 int mnt_context_mtab_writable(struct libmnt_context *cxt)
233 {
234 	assert(cxt);
235 
236 	context_init_paths(cxt, 1);
237 	return cxt->mtab_writable == 1;
238 }
239 
mnt_context_utab_writable(struct libmnt_context * cxt)240 int mnt_context_utab_writable(struct libmnt_context *cxt)
241 {
242 	assert(cxt);
243 
244 	context_init_paths(cxt, 1);
245 	return cxt->utab_writable == 1;
246 }
247 
mnt_context_get_writable_tabpath(struct libmnt_context * cxt)248 const char *mnt_context_get_writable_tabpath(struct libmnt_context *cxt)
249 {
250 	assert(cxt);
251 
252 	context_init_paths(cxt, 1);
253 	return cxt->mtab_writable ? cxt->mtab_path : cxt->utab_path;
254 }
255 
256 
set_flag(struct libmnt_context * cxt,int flag,int enable)257 static int set_flag(struct libmnt_context *cxt, int flag, int enable)
258 {
259 	assert(cxt);
260 	if (!cxt)
261 		return -EINVAL;
262 	if (enable) {
263 		DBG(CXT, ul_debugobj(cxt, "enabling flag %04x", flag));
264 		cxt->flags |= flag;
265 	} else {
266 		DBG(CXT, ul_debugobj(cxt, "disabling flag %04x", flag));
267 		cxt->flags &= ~flag;
268 	}
269 	return 0;
270 }
271 
272 /**
273  * mnt_context_is_restricted:
274  * @cxt: mount context
275  *
276  * Returns: 0 for an unrestricted mount (user is root), or 1 for non-root mounts
277  */
mnt_context_is_restricted(struct libmnt_context * cxt)278 int mnt_context_is_restricted(struct libmnt_context *cxt)
279 {
280 	return cxt->restricted;
281 }
282 
283 /**
284  * mnt_context_set_optsmode
285  * @cxt: mount context
286  * @mode: MNT_OMODE_* flags
287  *
288  * Controls how to use mount optionssource and target paths from fstab/mtab.
289  *
290  * @MNT_OMODE_IGNORE: ignore mtab/fstab options
291  *
292  * @MNT_OMODE_APPEND: append mtab/fstab options to existing options
293  *
294  * @MNT_OMODE_PREPEND: prepend mtab/fstab options to existing options
295  *
296  * @MNT_OMODE_REPLACE: replace existing options with options from mtab/fstab
297  *
298  * @MNT_OMODE_FORCE: always read mtab/fstab (although source and target are defined)
299  *
300  * @MNT_OMODE_FSTAB: read from fstab
301  *
302  * @MNT_OMODE_MTAB: read from mtab if fstab not enabled or failed
303  *
304  * @MNT_OMODE_NOTAB: do not read fstab/mtab at all
305  *
306  * @MNT_OMODE_AUTO: default mode (MNT_OMODE_PREPEND | MNT_OMODE_FSTAB | MNT_OMODE_MTAB)
307  *
308  * @MNT_OMODE_USER: default for non-root users (MNT_OMODE_REPLACE | MNT_OMODE_FORCE | MNT_OMODE_FSTAB)
309  *
310  * Notes:
311  *
312  * - MNT_OMODE_USER is always used if mount context is in restricted mode
313  * - MNT_OMODE_AUTO is used if nothing else is defined
314  * - the flags are evaluated in this order: MNT_OMODE_NOTAB, MNT_OMODE_FORCE,
315  *   MNT_OMODE_FSTAB, MNT_OMODE_MTAB and then the mount options from fstab/mtab
316  *   are set according to MNT_OMODE_{IGNORE,APPEND,PREPAND,REPLACE}
317  *
318  * Returns: 0 on success, negative number in case of error.
319  */
mnt_context_set_optsmode(struct libmnt_context * cxt,int mode)320 int mnt_context_set_optsmode(struct libmnt_context *cxt, int mode)
321 {
322 	assert(cxt);
323 	if (!cxt)
324 		return -EINVAL;
325 	cxt->optsmode = mode;
326 	return 0;
327 }
328 
329 /**
330  * mnt_context_get_optsmode
331  * @cxt: mount context
332  *
333  * Returns: MNT_OMODE_* mask or zero.
334  */
335 
mnt_context_get_optsmode(struct libmnt_context * cxt)336 int mnt_context_get_optsmode(struct libmnt_context *cxt)
337 {
338 	assert(cxt);
339 	return cxt->optsmode;
340 }
341 
342 /**
343  * mnt_context_disable_canonicalize:
344  * @cxt: mount context
345  * @disable: TRUE or FALSE
346  *
347  * Enable/disable paths canonicalization and tags evaluation. The libmount context
348  * canonicalizes paths when searching in fstab and when preparing source and target paths
349  * for mount(2) syscall.
350  *
351  * This fuction has an effect on the private (within context) fstab instance only
352  * (see mnt_context_set_fstab()). If you want to use an external fstab then you
353  * need to manage your private struct libmnt_cache (see mnt_table_set_cache(fstab,
354  * NULL).
355  *
356  * Returns: 0 on success, negative number in case of error.
357  */
mnt_context_disable_canonicalize(struct libmnt_context * cxt,int disable)358 int mnt_context_disable_canonicalize(struct libmnt_context *cxt, int disable)
359 {
360 	return set_flag(cxt, MNT_FL_NOCANONICALIZE, disable);
361 }
362 
363 /**
364  * mnt_context_is_nocanonicalize:
365  * @cxt: mount context
366  *
367  * Returns: 1 if no-canonicalize mode is enabled or 0.
368  */
mnt_context_is_nocanonicalize(struct libmnt_context * cxt)369 int mnt_context_is_nocanonicalize(struct libmnt_context *cxt)
370 {
371 	return cxt && (cxt->flags & MNT_FL_NOCANONICALIZE) ? 1 : 0;
372 }
373 
374 /**
375  * mnt_context_enable_lazy:
376  * @cxt: mount context
377  * @enable: TRUE or FALSE
378  *
379  * Enable/disable lazy umount (see umount(8) man page, option -l).
380  *
381  * Returns: 0 on success, negative number in case of error.
382  */
mnt_context_enable_lazy(struct libmnt_context * cxt,int enable)383 int mnt_context_enable_lazy(struct libmnt_context *cxt, int enable)
384 {
385 	return set_flag(cxt, MNT_FL_LAZY, enable);
386 }
387 
388 /**
389  * mnt_context_is_lazy:
390  * @cxt: mount context
391  *
392  * Returns: 1 if lazy umount is enabled or 0
393  */
mnt_context_is_lazy(struct libmnt_context * cxt)394 int mnt_context_is_lazy(struct libmnt_context *cxt)
395 {
396 	return cxt->flags & MNT_FL_LAZY ? 1 : 0;
397 }
398 
399 /**
400  * mnt_context_enable_fork:
401  * @cxt: mount context
402  * @enable: TRUE or FALSE
403  *
404  * Enable/disable fork(2) call in mnt_context_next_mount() (see mount(8) man
405  * page, option -F).
406  *
407  * Returns: 0 on success, negative number in case of error.
408  */
mnt_context_enable_fork(struct libmnt_context * cxt,int enable)409 int mnt_context_enable_fork(struct libmnt_context *cxt, int enable)
410 {
411 	return set_flag(cxt, MNT_FL_FORK, enable);
412 }
413 
414 /**
415  * mnt_context_is_fork:
416  * @cxt: mount context
417  *
418  * Returns: 1 if fork (mount -F) is enabled or 0
419  */
mnt_context_is_fork(struct libmnt_context * cxt)420 int mnt_context_is_fork(struct libmnt_context *cxt)
421 {
422 	return cxt->flags & MNT_FL_FORK ? 1 : 0;
423 }
424 
425 /**
426  * mnt_context_is_parent:
427  * @cxt: mount context
428  *
429  * Return: 1 if mount -F enabled and the current context is parent, or 0
430  */
mnt_context_is_parent(struct libmnt_context * cxt)431 int mnt_context_is_parent(struct libmnt_context *cxt)
432 {
433 	return mnt_context_is_fork(cxt) && cxt->pid == 0;
434 }
435 
436 /**
437  * mnt_context_is_child:
438  * @cxt: mount context
439  *
440  * Return: 1 f the current context is child, or 0
441  */
mnt_context_is_child(struct libmnt_context * cxt)442 int mnt_context_is_child(struct libmnt_context *cxt)
443 {
444 	/* See mnt_fork_context(), the for fork flag is always disabled
445 	 * for children to avoid recursive forking.
446 	 */
447 	return !mnt_context_is_fork(cxt) && cxt->pid;
448 }
449 
450 /**
451  * mnt_context_enable_rdonly_umount:
452  * @cxt: mount context
453  * @enable: TRUE or FALSE
454  *
455  * Enable/disable read-only remount on failed umount(2)
456  * (see umount(8) man page, option -r).
457  *
458  * Returns: 0 on success, negative number in case of error.
459  */
mnt_context_enable_rdonly_umount(struct libmnt_context * cxt,int enable)460 int mnt_context_enable_rdonly_umount(struct libmnt_context *cxt, int enable)
461 {
462 	return set_flag(cxt, MNT_FL_RDONLY_UMOUNT, enable);
463 }
464 
465 /**
466  * mnt_context_is_rdonly_umount
467  * @cxt: mount context
468  *
469  * See also mnt_context_enable_rdonly_umount() and umount(8) man page,
470  * option -r.
471  *
472  * Returns: 1 if read-only remount failed umount(2) is enables or 0
473  */
mnt_context_is_rdonly_umount(struct libmnt_context * cxt)474 int mnt_context_is_rdonly_umount(struct libmnt_context *cxt)
475 {
476 	return cxt->flags & MNT_FL_RDONLY_UMOUNT ? 1 : 0;
477 }
478 
479 /**
480  * mnt_context_disable_helpers:
481  * @cxt: mount context
482  * @disable: TRUE or FALSE
483  *
484  * Enable/disable /sbin/[u]mount.* helpers (see mount(8) man page, option -i).
485  *
486  * Returns: 0 on success, negative number in case of error.
487  */
mnt_context_disable_helpers(struct libmnt_context * cxt,int disable)488 int mnt_context_disable_helpers(struct libmnt_context *cxt, int disable)
489 {
490 	return set_flag(cxt, MNT_FL_NOHELPERS, disable);
491 }
492 
493 /**
494  * mnt_context_is_nohelpers
495  * @cxt: mount context
496  *
497  * Returns: 1 if helpers are disabled (mount -i) or 0
498  */
mnt_context_is_nohelpers(struct libmnt_context * cxt)499 int mnt_context_is_nohelpers(struct libmnt_context *cxt)
500 {
501 	return cxt->flags & MNT_FL_NOHELPERS ? 1 : 0;
502 }
503 
504 
505 /**
506  * mnt_context_enable_sloppy:
507  * @cxt: mount context
508  * @enable: TRUE or FALSE
509  *
510  * Set/unset sloppy mounting (see mount(8) man page, option -s).
511  *
512  * Returns: 0 on success, negative number in case of error.
513  */
mnt_context_enable_sloppy(struct libmnt_context * cxt,int enable)514 int mnt_context_enable_sloppy(struct libmnt_context *cxt, int enable)
515 {
516 	return set_flag(cxt, MNT_FL_SLOPPY, enable);
517 }
518 
519 /**
520  * mnt_context_is_sloppy:
521  * @cxt: mount context
522  *
523  * Returns: 1 if sloppy flag is enabled or 0
524  */
mnt_context_is_sloppy(struct libmnt_context * cxt)525 int mnt_context_is_sloppy(struct libmnt_context *cxt)
526 {
527 	return cxt->flags & MNT_FL_SLOPPY ? 1 : 0;
528 }
529 
530 /**
531  * mnt_context_enable_fake:
532  * @cxt: mount context
533  * @enable: TRUE or FALSE
534  *
535  * Enable/disable fake mounting (see mount(8) man page, option -f).
536  *
537  * Returns: 0 on success, negative number in case of error.
538  */
mnt_context_enable_fake(struct libmnt_context * cxt,int enable)539 int mnt_context_enable_fake(struct libmnt_context *cxt, int enable)
540 {
541 	return set_flag(cxt, MNT_FL_FAKE, enable);
542 }
543 
544 /**
545  * mnt_context_is_fake:
546  * @cxt: mount context
547  *
548  * Returns: 1 if fake flag is enabled or 0
549  */
mnt_context_is_fake(struct libmnt_context * cxt)550 int mnt_context_is_fake(struct libmnt_context *cxt)
551 {
552 	return cxt->flags & MNT_FL_FAKE ? 1 : 0;
553 }
554 
555 /**
556  * mnt_context_disable_mtab:
557  * @cxt: mount context
558  * @disable: TRUE or FALSE
559  *
560  * Disable/enable mtab update (see mount(8) man page, option -n).
561  *
562  * Returns: 0 on success, negative number in case of error.
563  */
mnt_context_disable_mtab(struct libmnt_context * cxt,int disable)564 int mnt_context_disable_mtab(struct libmnt_context *cxt, int disable)
565 {
566 	return set_flag(cxt, MNT_FL_NOMTAB, disable);
567 }
568 
569 /**
570  * mnt_context_is_nomtab:
571  * @cxt: mount context
572  *
573  * Returns: 1 if no-mtab is enabled or 0
574  */
mnt_context_is_nomtab(struct libmnt_context * cxt)575 int mnt_context_is_nomtab(struct libmnt_context *cxt)
576 {
577 	return cxt->flags & MNT_FL_NOMTAB ? 1 : 0;
578 }
579 
580 /**
581  * mnt_context_disable_swapmatch:
582  * @cxt: mount context
583  * @disable: TRUE or FALSE
584  *
585  * Disable/enable swap between source and target for mount(8) if only one path
586  * is specified.
587  *
588  * Returns: 0 on success, negative number in case of error.
589  */
mnt_context_disable_swapmatch(struct libmnt_context * cxt,int disable)590 int mnt_context_disable_swapmatch(struct libmnt_context *cxt, int disable)
591 {
592 	return set_flag(cxt, MNT_FL_NOSWAPMATCH, disable);
593 }
594 
595 /**
596  * mnt_context_is_swapmatch:
597  * @cxt: mount context
598  *
599  * Returns: 1 if swap between source and target is allowed (default is 1) or 0.
600  */
mnt_context_is_swapmatch(struct libmnt_context * cxt)601 int mnt_context_is_swapmatch(struct libmnt_context *cxt)
602 {
603 	return cxt->flags & MNT_FL_NOSWAPMATCH ? 0 : 1;
604 }
605 
606 /**
607  * mnt_context_enable_force:
608  * @cxt: mount context
609  * @enable: TRUE or FALSE
610  *
611  * Enable/disable force umounting (see umount(8) man page, option -f).
612  *
613  * Returns: 0 on success, negative number in case of error.
614  */
mnt_context_enable_force(struct libmnt_context * cxt,int enable)615 int mnt_context_enable_force(struct libmnt_context *cxt, int enable)
616 {
617 	return set_flag(cxt, MNT_FL_FORCE, enable);
618 }
619 
620 /**
621  * mnt_context_is_force
622  * @cxt: mount context
623  *
624  * Returns: 1 if force umounting flag is enabled or 0
625  */
mnt_context_is_force(struct libmnt_context * cxt)626 int mnt_context_is_force(struct libmnt_context *cxt)
627 {
628 	return cxt->flags & MNT_FL_FORCE ? 1 : 0;
629 }
630 
631 /**
632  * mnt_context_enable_verbose:
633  * @cxt: mount context
634  * @enable: TRUE or FALSE
635  *
636  * Enable/disable verbose output (TODO: not implemented yet)
637  *
638  * Returns: 0 on success, negative number in case of error.
639  */
mnt_context_enable_verbose(struct libmnt_context * cxt,int enable)640 int mnt_context_enable_verbose(struct libmnt_context *cxt, int enable)
641 {
642 	return set_flag(cxt, MNT_FL_VERBOSE, enable);
643 }
644 
645 /**
646  * mnt_context_is_verbose
647  * @cxt: mount context
648  *
649  * Returns: 1 if verbose flag is enabled or 0
650  */
mnt_context_is_verbose(struct libmnt_context * cxt)651 int mnt_context_is_verbose(struct libmnt_context *cxt)
652 {
653 	return cxt->flags & MNT_FL_VERBOSE ? 1 : 0;
654 }
655 
656 /**
657  * mnt_context_enable_loopdel:
658  * @cxt: mount context
659  * @enable: TRUE or FALSE
660  *
661  * Enable/disable the loop delete (destroy) after umount (see umount(8), option -d)
662  *
663  * Returns: 0 on success, negative number in case of error.
664  */
mnt_context_enable_loopdel(struct libmnt_context * cxt,int enable)665 int mnt_context_enable_loopdel(struct libmnt_context *cxt, int enable)
666 {
667 	return set_flag(cxt, MNT_FL_LOOPDEL, enable);
668 }
669 
670 /**
671  * mnt_context_is_loopdel:
672  * @cxt: mount context
673  *
674  * Returns: 1 if loop device should be deleted after umount (umount -d) or 0.
675  */
mnt_context_is_loopdel(struct libmnt_context * cxt)676 int mnt_context_is_loopdel(struct libmnt_context *cxt)
677 {
678 	return cxt->flags & MNT_FL_LOOPDEL ? 1 : 0;
679 }
680 
681 /**
682  * mnt_context_set_fs:
683  * @cxt: mount context
684  * @fs: filesystem description
685  *
686  * The mount context uses private @fs by default. This function allows to
687  * overwrite the private @fs with an external instance. This function
688  * increments @fs reference counter (and deincrement reference counter of the
689  * old fs).
690  *
691  * The @fs will be modified by mnt_context_set_{source,target,options,fstype}
692  * functions, If the @fs is NULL, then all current FS specific settings (source,
693  * target, etc., exclude spec) are reset.
694  *
695  * Returns: 0 on success, negative number in case of error.
696  */
mnt_context_set_fs(struct libmnt_context * cxt,struct libmnt_fs * fs)697 int mnt_context_set_fs(struct libmnt_context *cxt, struct libmnt_fs *fs)
698 {
699 	if (!cxt)
700 		return -EINVAL;
701 
702 	mnt_ref_fs(fs);			/* new */
703 	mnt_unref_fs(cxt->fs);		/* old */
704 	cxt->fs = fs;
705 	return 0;
706 }
707 
708 /**
709  * mnt_context_get_fs:
710  * @cxt: mount context
711  *
712  * The FS contains the basic description of mountpoint, fs type and so on.
713  * Note that the FS is modified by mnt_context_set_{source,target,options,fstype}
714  * functions.
715  *
716  * Returns: pointer to FS description or NULL in case of a calloc() error.
717  */
mnt_context_get_fs(struct libmnt_context * cxt)718 struct libmnt_fs *mnt_context_get_fs(struct libmnt_context *cxt)
719 {
720 	assert(cxt);
721 	if (!cxt)
722 		return NULL;
723 	if (!cxt->fs)
724 		cxt->fs = mnt_new_fs();
725 	return cxt->fs;
726 }
727 
728 /**
729  * mnt_context_get_fs_userdata:
730  * @cxt: mount context
731  *
732  * Returns: pointer to userdata or NULL.
733  */
mnt_context_get_fs_userdata(struct libmnt_context * cxt)734 void *mnt_context_get_fs_userdata(struct libmnt_context *cxt)
735 {
736 	assert(cxt);
737 	return cxt->fs ? mnt_fs_get_userdata(cxt->fs) : NULL;
738 }
739 
740 /**
741  * mnt_context_get_fstab_userdata:
742  * @cxt: mount context
743  *
744  * Returns: pointer to userdata or NULL.
745  */
mnt_context_get_fstab_userdata(struct libmnt_context * cxt)746 void *mnt_context_get_fstab_userdata(struct libmnt_context *cxt)
747 {
748 	assert(cxt);
749 	return cxt->fstab ? mnt_table_get_userdata(cxt->fstab) : NULL;
750 }
751 
752 /**
753  * mnt_context_get_mtab_userdata:
754  * @cxt: mount context
755  *
756  * Returns: pointer to userdata or NULL.
757  */
mnt_context_get_mtab_userdata(struct libmnt_context * cxt)758 void *mnt_context_get_mtab_userdata(struct libmnt_context *cxt)
759 {
760 	assert(cxt);
761 	return cxt->mtab ? mnt_table_get_userdata(cxt->mtab) : NULL;
762 }
763 
764 /**
765  * mnt_context_set_source:
766  * @cxt: mount context
767  * @source: mount source (device, directory, UUID, LABEL, ...)
768  *
769  * Note that libmount does not interpret "nofail" (MNT_MS_NOFAIL)
770  * mount option. The real return code is always returned, when
771  * the device does not exist then it's usually MNT_ERR_NOSOURCE
772  * from libmount or ENOENT, ENOTDIR, ENOTBLK, ENXIO from moun(2).
773  *
774  * Returns: 0 on success, negative number in case of error.
775  */
mnt_context_set_source(struct libmnt_context * cxt,const char * source)776 int mnt_context_set_source(struct libmnt_context *cxt, const char *source)
777 {
778 	assert(cxt);
779 	return mnt_fs_set_source(mnt_context_get_fs(cxt), source);
780 }
781 
782 /**
783  * mnt_context_get_source:
784  * @cxt: mount context
785  *
786  * Returns: returns pointer or NULL in case of error or if not set.
787  */
mnt_context_get_source(struct libmnt_context * cxt)788 const char *mnt_context_get_source(struct libmnt_context *cxt)
789 {
790 	assert(cxt);
791 	return mnt_fs_get_source(mnt_context_get_fs(cxt));
792 }
793 
794 /**
795  * mnt_context_set_target:
796  * @cxt: mount context
797  * @target: mountpoint
798  *
799  * Returns: 0 on success, negative number in case of error.
800  */
mnt_context_set_target(struct libmnt_context * cxt,const char * target)801 int mnt_context_set_target(struct libmnt_context *cxt, const char *target)
802 {
803 	assert(cxt);
804 	return mnt_fs_set_target(mnt_context_get_fs(cxt), target);
805 }
806 
807 /**
808  * mnt_context_get_target:
809  * @cxt: mount context
810  *
811  * Returns: returns pointer or NULL in case of error or if not set.
812  */
mnt_context_get_target(struct libmnt_context * cxt)813 const char *mnt_context_get_target(struct libmnt_context *cxt)
814 {
815 	assert(cxt);
816 	return mnt_fs_get_target(mnt_context_get_fs(cxt));
817 }
818 
819 /**
820  * mnt_context_set_fstype:
821  * @cxt: mount context
822  * @fstype: filesystem type
823  *
824  * Note that the @fstype has to be a FS type. For patterns with
825  * comma-separated list of filesystems or for the "nofs" notation, use
826  * mnt_context_set_fstype_pattern().
827  *
828  * Returns: 0 on success, negative number in case of error.
829  */
mnt_context_set_fstype(struct libmnt_context * cxt,const char * fstype)830 int mnt_context_set_fstype(struct libmnt_context *cxt, const char *fstype)
831 {
832 	assert(cxt);
833 	return mnt_fs_set_fstype(mnt_context_get_fs(cxt), fstype);
834 }
835 
836 /**
837  * mnt_context_get_fstype:
838  * @cxt: mount context
839  *
840  * Returns: pointer or NULL in case of error or if not set.
841  */
mnt_context_get_fstype(struct libmnt_context * cxt)842 const char *mnt_context_get_fstype(struct libmnt_context *cxt)
843 {
844 	assert(cxt);
845 	return mnt_fs_get_fstype(mnt_context_get_fs(cxt));
846 }
847 
848 /**
849  * mnt_context_set_options:
850  * @cxt: mount context
851  * @optstr: comma delimited mount options
852  *
853  * Returns: 0 on success, negative number in case of error.
854  */
mnt_context_set_options(struct libmnt_context * cxt,const char * optstr)855 int mnt_context_set_options(struct libmnt_context *cxt, const char *optstr)
856 {
857 	assert(cxt);
858 	return mnt_fs_set_options(mnt_context_get_fs(cxt), optstr);
859 }
860 
861 /**
862  * mnt_context_append_options:
863  * @cxt: mount context
864  * @optstr: comma delimited mount options
865  *
866  * Returns: 0 on success, negative number in case of error.
867  */
mnt_context_append_options(struct libmnt_context * cxt,const char * optstr)868 int mnt_context_append_options(struct libmnt_context *cxt, const char *optstr)
869 {
870 	assert(cxt);
871 	return mnt_fs_append_options(mnt_context_get_fs(cxt), optstr);
872 }
873 
874 /**
875  * mnt_context_get_options:
876  * @cxt: mount context
877  *
878  * This function returns mount options set by mnt_context_set_options() or
879  * mnt_context_append_options().
880  *
881  * Note that *after* mnt_context_prepare_mount(), the mount options string
882  * may also include options set by mnt_context_set_mflags() or other options
883  * generated by this library.
884  *
885  * Returns: pointer or NULL
886  */
mnt_context_get_options(struct libmnt_context * cxt)887 const char *mnt_context_get_options(struct libmnt_context *cxt)
888 {
889 	assert(cxt);
890 	return mnt_fs_get_options(mnt_context_get_fs(cxt));
891 }
892 
893 /**
894  * mnt_context_set_fstype_pattern:
895  * @cxt: mount context
896  * @pattern: FS name pattern (or NULL to reset the current setting)
897  *
898  * See mount(8), option -t.
899  *
900  * Returns: 0 on success, negative number in case of error.
901  */
mnt_context_set_fstype_pattern(struct libmnt_context * cxt,const char * pattern)902 int mnt_context_set_fstype_pattern(struct libmnt_context *cxt, const char *pattern)
903 {
904 	char *p = NULL;
905 
906 	assert(cxt);
907 	if (!cxt)
908 		return -EINVAL;
909 	if (pattern) {
910 		p = strdup(pattern);
911 		if (!p)
912 			return -ENOMEM;
913 	}
914 	free(cxt->fstype_pattern);
915 	cxt->fstype_pattern = p;
916 	return 0;
917 }
918 
919 /**
920  * mnt_context_set_options_pattern:
921  * @cxt: mount context
922  * @pattern: options pattern (or NULL to reset the current setting)
923  *
924  * See mount(8), option -O.
925  *
926  * Returns: 0 on success, negative number in case of error.
927  */
mnt_context_set_options_pattern(struct libmnt_context * cxt,const char * pattern)928 int mnt_context_set_options_pattern(struct libmnt_context *cxt, const char *pattern)
929 {
930 	char *p = NULL;
931 
932 	assert(cxt);
933 	if (!cxt)
934 		return -EINVAL;
935 	if (pattern) {
936 		p = strdup(pattern);
937 		if (!p)
938 			return -ENOMEM;
939 	}
940 	free(cxt->optstr_pattern);
941 	cxt->optstr_pattern = p;
942 	return 0;
943 }
944 
945 /**
946  * mnt_context_set_fstab:
947  * @cxt: mount context
948  * @tb: fstab
949  *
950  * The mount context reads /etc/fstab to the private struct libmnt_table by default.
951  * This function allows to overwrite the private fstab with an external
952  * instance.
953  *
954  * This function modify the @tb reference counter. This function does not set
955  * the cache for the @tb. You have to explicitly call mnt_table_set_cache(tb,
956  * mnt_context_get_cache(cxt));
957  *
958  * The fstab is used read-only and is not modified, it should be possible to
959  * share the fstab between more mount contexts (TODO: test it.)
960  *
961  * If the @tb argument is NULL, then the current private fstab instance is
962  * reset.
963  *
964  * Returns: 0 on success, negative number in case of error.
965  */
mnt_context_set_fstab(struct libmnt_context * cxt,struct libmnt_table * tb)966 int mnt_context_set_fstab(struct libmnt_context *cxt, struct libmnt_table *tb)
967 {
968 	assert(cxt);
969 	if (!cxt)
970 		return -EINVAL;
971 
972 	mnt_ref_table(tb);		/* new */
973 	mnt_unref_table(cxt->fstab);	/* old */
974 
975 	cxt->fstab = tb;
976 	return 0;
977 }
978 
979 /**
980  * mnt_context_get_fstab:
981  * @cxt: mount context
982  * @tb: returns fstab
983  *
984  * See also mnt_table_parse_fstab() for more details about fstab.
985  *
986  * Returns: 0 on success, negative number in case of error.
987  */
mnt_context_get_fstab(struct libmnt_context * cxt,struct libmnt_table ** tb)988 int mnt_context_get_fstab(struct libmnt_context *cxt, struct libmnt_table **tb)
989 {
990 	assert(cxt);
991 	if (!cxt)
992 		return -EINVAL;
993 	if (!cxt->fstab) {
994 		int rc;
995 
996 		cxt->fstab = mnt_new_table();
997 		if (!cxt->fstab)
998 			return -ENOMEM;
999 		if (cxt->table_errcb)
1000 			mnt_table_set_parser_errcb(cxt->fstab, cxt->table_errcb);
1001 		mnt_table_set_cache(cxt->fstab, mnt_context_get_cache(cxt));
1002 		rc = mnt_table_parse_fstab(cxt->fstab, NULL);
1003 		if (rc)
1004 			return rc;
1005 	}
1006 
1007 	if (tb)
1008 		*tb = cxt->fstab;
1009 	return 0;
1010 }
1011 
1012 /**
1013  * mnt_context_get_mtab:
1014  * @cxt: mount context
1015  * @tb: returns mtab
1016  *
1017  * See also mnt_table_parse_mtab() for more details about mtab/mountinfo. The
1018  * result will be deallocated by mnt_free_context(@cxt).
1019  *
1020  * Returns: 0 on success, negative number in case of error.
1021  */
mnt_context_get_mtab(struct libmnt_context * cxt,struct libmnt_table ** tb)1022 int mnt_context_get_mtab(struct libmnt_context *cxt, struct libmnt_table **tb)
1023 {
1024 	assert(cxt);
1025 	if (!cxt)
1026 		return -EINVAL;
1027 	if (!cxt->mtab) {
1028 		int rc;
1029 
1030 		context_init_paths(cxt, 0);
1031 
1032 		cxt->mtab = mnt_new_table();
1033 		if (!cxt->mtab)
1034 			return -ENOMEM;
1035 
1036 		if (cxt->table_errcb)
1037 			mnt_table_set_parser_errcb(cxt->mtab, cxt->table_errcb);
1038 		if (cxt->table_fltrcb)
1039 			mnt_table_set_parser_fltrcb(cxt->mtab,
1040 					cxt->table_fltrcb,
1041 					cxt->table_fltrcb_data);
1042 
1043 		mnt_table_set_cache(cxt->mtab, mnt_context_get_cache(cxt));
1044 		if (cxt->utab)
1045 			/* utab already parsed, don't parse it again */
1046 			rc = __mnt_table_parse_mtab(cxt->mtab,
1047 						    cxt->mtab_path, cxt->utab);
1048 		else
1049 			rc = mnt_table_parse_mtab(cxt->mtab, cxt->mtab_path);
1050 		if (rc)
1051 			return rc;
1052 	}
1053 
1054 	if (tb)
1055 		*tb = cxt->mtab;
1056 
1057 	DBG(CXT, ul_debugobj(cxt, "mtab requested [nents=%d]",
1058 				mnt_table_get_nents(cxt->mtab)));
1059 	return 0;
1060 }
1061 
1062 /*
1063  * Allows to specify a filter for tab file entries. The filter is called by
1064  * the table parser. Currently used for mtab and utab only.
1065  */
mnt_context_set_tabfilter(struct libmnt_context * cxt,int (* fltr)(struct libmnt_fs *,void *),void * data)1066 int mnt_context_set_tabfilter(struct libmnt_context *cxt,
1067 			      int (*fltr)(struct libmnt_fs *, void *),
1068 			      void *data)
1069 {
1070 	assert(cxt);
1071 	if (!cxt)
1072 		return -EINVAL;
1073 
1074 	cxt->table_fltrcb = fltr;
1075 	cxt->table_fltrcb_data = data;
1076 
1077 	if (cxt->mtab)
1078 		mnt_table_set_parser_fltrcb(cxt->mtab,
1079 				cxt->table_fltrcb,
1080 				cxt->table_fltrcb_data);
1081 
1082 	DBG(CXT, ul_debugobj(cxt, "tabfilter %s", fltr ? "ENABLED!" : "disabled"));
1083 	return 0;
1084 }
1085 
1086 /**
1087  * mnt_context_get_table:
1088  * @cxt: mount context
1089  * @filename: e.g. /proc/self/mountinfo
1090  * @tb: returns the table
1091  *
1092  * This function allocates a new table and parses the @file. The parser error
1093  * callback and cache for tags and paths is set according to the @cxt setting.
1094  * See also mnt_table_parse_file().
1095  *
1096  * It's strongly recommended to use the mnt_context_get_mtab() and
1097  * mnt_context_get_fstab() functions for mtab and fstab files. This function
1098  * does not care about LIBMOUNT_* env.variables and does not merge userspace
1099  * options.
1100  *
1101  * The result will NOT be deallocated by mnt_free_context(@cxt).
1102  *
1103  * Returns: 0 on success, negative number in case of error.
1104  */
mnt_context_get_table(struct libmnt_context * cxt,const char * filename,struct libmnt_table ** tb)1105 int mnt_context_get_table(struct libmnt_context *cxt,
1106 			  const char *filename, struct libmnt_table **tb)
1107 {
1108 	int rc;
1109 
1110 	assert(cxt);
1111 	assert(tb);
1112 	if (!cxt || !tb)
1113 		return -EINVAL;
1114 
1115 	*tb = mnt_new_table();
1116 	if (!*tb)
1117 		return -ENOMEM;
1118 
1119 	if (cxt->table_errcb)
1120 		mnt_table_set_parser_errcb(*tb, cxt->table_errcb);
1121 
1122 	rc = mnt_table_parse_file(*tb, filename);
1123 	if (rc) {
1124 		mnt_unref_table(*tb);
1125 		return rc;
1126 	}
1127 
1128 	mnt_table_set_cache(*tb, mnt_context_get_cache(cxt));
1129 	return 0;
1130 }
1131 
1132 /**
1133  * mnt_context_set_tables_errcb
1134  * @cxt: mount context
1135  * @cb: pointer to callback function
1136  *
1137  * The error callback is used for all tab files (e.g. mtab, fstab)
1138  * parsed within the context.
1139  *
1140  * See also mnt_context_get_mtab(),
1141  *          mnt_context_get_fstab(),
1142  *          mnt_table_set_parser_errcb().
1143  *
1144  * Returns: 0 on success, negative number in case of error.
1145  */
mnt_context_set_tables_errcb(struct libmnt_context * cxt,int (* cb)(struct libmnt_table * tb,const char * filename,int line))1146 int mnt_context_set_tables_errcb(struct libmnt_context *cxt,
1147 	int (*cb)(struct libmnt_table *tb, const char *filename, int line))
1148 {
1149 	assert(cxt);
1150 	if (!cxt)
1151 		return -EINVAL;
1152 
1153 	if (cxt->mtab)
1154 		mnt_table_set_parser_errcb(cxt->mtab, cb);
1155 	if (cxt->fstab)
1156 		mnt_table_set_parser_errcb(cxt->fstab, cb);
1157 
1158 	cxt->table_errcb = cb;
1159 	return 0;
1160 }
1161 
1162 /**
1163  * mnt_context_set_cache:
1164  * @cxt: mount context
1165  * @cache: cache instance or nULL
1166  *
1167  * The mount context maintains a private struct libmnt_cache by default. This
1168  * function allows to overwrite the private cache with an external instance.
1169  * This function increments cache reference counter.
1170  *
1171  * If the @cache argument is NULL, then the current cache instance is reset.
1172  * This function apply the cache to fstab and mtab instances (if already
1173  * exists).
1174  *
1175  * The old cache instance reference counter is de-incremented.
1176  *
1177  * Returns: 0 on success, negative number in case of error.
1178  */
mnt_context_set_cache(struct libmnt_context * cxt,struct libmnt_cache * cache)1179 int mnt_context_set_cache(struct libmnt_context *cxt, struct libmnt_cache *cache)
1180 {
1181 	if (!cxt)
1182 		return -EINVAL;
1183 
1184 	mnt_ref_cache(cache);			/* new */
1185 	mnt_unref_cache(cxt->cache);		/* old */
1186 
1187 	cxt->cache = cache;
1188 
1189 	if (cxt->mtab)
1190 		mnt_table_set_cache(cxt->mtab, cache);
1191 	if (cxt->fstab)
1192 		mnt_table_set_cache(cxt->fstab, cache);
1193 
1194 	return 0;
1195 }
1196 
1197 /**
1198  * mnt_context_get_cache
1199  * @cxt: mount context
1200  *
1201  * See also mnt_context_set_cache().
1202  *
1203  * Returns: pointer to cache or NULL if canonicalization is disabled.
1204  */
mnt_context_get_cache(struct libmnt_context * cxt)1205 struct libmnt_cache *mnt_context_get_cache(struct libmnt_context *cxt)
1206 {
1207 	assert(cxt);
1208 	if (!cxt || mnt_context_is_nocanonicalize(cxt))
1209 		return NULL;
1210 
1211 	if (!cxt->cache) {
1212 		struct libmnt_cache *cache = mnt_new_cache();
1213 		mnt_context_set_cache(cxt, cache);
1214 		mnt_unref_cache(cache);
1215 	}
1216 	return cxt->cache;
1217 }
1218 
1219 /**
1220  * mnt_context_set_passwd_cb:
1221  * @cxt: mount context
1222  * @get: callback to get password
1223  * @release: callback to release (delallocate) password
1224  *
1225  * Sets callbacks for encryption password (e.g encrypted loopdev). This
1226  * function is deprecated (encrypted loops are no longer supported).
1227  *
1228  * Returns: 0 on success, negative number in case of error.
1229  */
mnt_context_set_passwd_cb(struct libmnt_context * cxt,char * (* get)(struct libmnt_context *),void (* release)(struct libmnt_context *,char *))1230 int mnt_context_set_passwd_cb(struct libmnt_context *cxt,
1231 			      char *(*get)(struct libmnt_context *),
1232 			      void (*release)(struct libmnt_context *, char *))
1233 {
1234 	assert(cxt);
1235 	if (!cxt)
1236 		return -EINVAL;
1237 	cxt->pwd_get_cb = get;
1238 	cxt->pwd_release_cb = release;
1239 	return 0;
1240 }
1241 
1242 /**
1243  * mnt_context_get_lock:
1244  * @cxt: mount context
1245  *
1246  * The libmount applications don't have to care about mtab locking, but with a
1247  * small exception: the application has to be able to remove the lock file when
1248  * interrupted by signal or signals have to be ignored when the lock is locked.
1249  *
1250  * The default behavior is to ignore all signals (except SIGALRM and
1251  * SIGTRAP for mtab udate) when the lock is locked. If this behavior
1252  * is unacceptable, then use:
1253  *
1254  *	lc = mnt_context_get_lock(cxt);
1255  *	if (lc)
1256  *		mnt_lock_block_signals(lc, FALSE);
1257  *
1258  * and don't forget to call mnt_unlock_file(lc) before exit.
1259  *
1260  * Returns: pointer to lock struct or NULL.
1261  */
mnt_context_get_lock(struct libmnt_context * cxt)1262 struct libmnt_lock *mnt_context_get_lock(struct libmnt_context *cxt)
1263 {
1264 	assert(cxt);
1265 	/*
1266 	 * DON'T call this function within libmount, it will always allocate
1267 	 * the lock. The mnt_update_* functions are able to allocate the lock
1268 	 * only when mtab/utab update is really necessary.
1269 	 */
1270 	if (!cxt || mnt_context_is_nomtab(cxt))
1271 		return NULL;
1272 
1273 	if (!cxt->lock) {
1274 		cxt->lock = mnt_new_lock(
1275 				mnt_context_get_writable_tabpath(cxt), 0);
1276 		if (cxt->lock)
1277 			mnt_lock_block_signals(cxt->lock, TRUE);
1278 	}
1279 	return cxt->lock;
1280 }
1281 
1282 /**
1283  * mnt_context_set_mflags:
1284  * @cxt: mount context
1285  * @flags: mount(2) flags (MS_* flags)
1286  *
1287  * Sets mount flags (see mount(2) man page).
1288  *
1289  * Note that mount context allows to define mount options by mount flags. It
1290  * means you can for example use
1291  *
1292  *	mnt_context_set_mflags(cxt, MS_NOEXEC | MS_NOSUID);
1293  *
1294  * rather than
1295  *
1296  *	mnt_context_set_options(cxt, "noexec,nosuid");
1297  *
1298  * both of these calls have the same effect.
1299  *
1300  * Returns: 0 on success, negative number in case of error.
1301  */
mnt_context_set_mflags(struct libmnt_context * cxt,unsigned long flags)1302 int mnt_context_set_mflags(struct libmnt_context *cxt, unsigned long flags)
1303 {
1304 	assert(cxt);
1305 	if (!cxt)
1306 		return -EINVAL;
1307 
1308 	cxt->mountflags = flags;
1309 
1310 	if ((cxt->flags & MNT_FL_MOUNTOPTS_FIXED) && cxt->fs)
1311 		/*
1312 		 * the final mount options are already generated, refresh...
1313 		 */
1314 		return mnt_optstr_apply_flags(
1315 				&cxt->fs->vfs_optstr,
1316 				cxt->mountflags,
1317 				mnt_get_builtin_optmap(MNT_LINUX_MAP));
1318 
1319 	return 0;
1320 }
1321 
1322 /**
1323  * mnt_context_get_mflags:
1324  * @cxt: mount context
1325  * @flags: returns MS_* mount flags
1326  *
1327  * Converts mount options string to MS_* flags and bitewise-OR the result with
1328  * the already defined flags (see mnt_context_set_mflags()).
1329  *
1330  * Returns: 0 on success, negative number in case of error.
1331  */
mnt_context_get_mflags(struct libmnt_context * cxt,unsigned long * flags)1332 int mnt_context_get_mflags(struct libmnt_context *cxt, unsigned long *flags)
1333 {
1334 	int rc = 0;
1335 	struct list_head *p;
1336 
1337 	assert(cxt);
1338 	assert(flags);
1339 	if (!cxt || !flags)
1340 		return -EINVAL;
1341 
1342 	*flags = 0;
1343 	if (!(cxt->flags & MNT_FL_MOUNTFLAGS_MERGED) && cxt->fs) {
1344 		const char *o = mnt_fs_get_options(cxt->fs);
1345 		if (o)
1346 			rc = mnt_optstr_get_flags(o, flags,
1347 				    mnt_get_builtin_optmap(MNT_LINUX_MAP));
1348 	}
1349 
1350 	list_for_each(p, &cxt->addmounts) {
1351 		struct libmnt_addmount *ad =
1352 				list_entry(p, struct libmnt_addmount, mounts);
1353 
1354 		*flags |= ad->mountflags;
1355 	}
1356 
1357 	if (!rc)
1358 		*flags |= cxt->mountflags;
1359 	return rc;
1360 }
1361 
1362 /**
1363  * mnt_context_set_user_mflags:
1364  * @cxt: mount context
1365  * @flags: mount(2) flags (MNT_MS_* flags, e.g. MNT_MS_LOOP)
1366  *
1367  * Sets userspace mount flags.
1368  *
1369  * See also notes for mnt_context_set_mflags().
1370  *
1371  * Returns: 0 on success, negative number in case of error.
1372  */
mnt_context_set_user_mflags(struct libmnt_context * cxt,unsigned long flags)1373 int mnt_context_set_user_mflags(struct libmnt_context *cxt, unsigned long flags)
1374 {
1375 	assert(cxt);
1376 	if (!cxt)
1377 		return -EINVAL;
1378 	cxt->user_mountflags = flags;
1379 	return 0;
1380 }
1381 
1382 /**
1383  * mnt_context_get_user_mflags:
1384  * @cxt: mount context
1385  * @flags: returns mount flags
1386  *
1387  * Converts mount options string to MNT_MS_* flags and bitewise-OR the result
1388  * with the already defined flags (see mnt_context_set_user_mflags()).
1389  *
1390  * Returns: 0 on success, negative number in case of error.
1391  */
mnt_context_get_user_mflags(struct libmnt_context * cxt,unsigned long * flags)1392 int mnt_context_get_user_mflags(struct libmnt_context *cxt, unsigned long *flags)
1393 {
1394 	int rc = 0;
1395 
1396 	assert(cxt);
1397 	assert(flags);
1398 	if (!cxt || !flags)
1399 		return -EINVAL;
1400 
1401 	*flags = 0;
1402 	if (!(cxt->flags & MNT_FL_MOUNTFLAGS_MERGED) && cxt->fs) {
1403 		const char *o = mnt_fs_get_user_options(cxt->fs);
1404 		if (o)
1405 			rc = mnt_optstr_get_flags(o, flags,
1406 				mnt_get_builtin_optmap(MNT_USERSPACE_MAP));
1407 	}
1408 	if (!rc)
1409 		*flags |= cxt->user_mountflags;
1410 	return rc;
1411 }
1412 
1413 /**
1414  * mnt_context_set_mountdata:
1415  * @cxt: mount context
1416  * @data: mount(2) data
1417  *
1418  * The mount context generates mountdata from mount options by default. This
1419  * function allows to overwrite this behavior, and @data will be used instead
1420  * of mount options.
1421  *
1422  * The libmount does not deallocate the data by mnt_free_context(). Note that
1423  * NULL is also valid mount data.
1424  *
1425  * Returns: 0 on success, negative number in case of error.
1426  */
mnt_context_set_mountdata(struct libmnt_context * cxt,void * data)1427 int mnt_context_set_mountdata(struct libmnt_context *cxt, void *data)
1428 {
1429 	assert(cxt);
1430 	if (!cxt)
1431 		return -EINVAL;
1432 	cxt->mountdata = data;
1433 	cxt->flags |= MNT_FL_MOUNTDATA;
1434 	return 0;
1435 }
1436 
1437 /*
1438  * Translates LABEL/UUID/path to mountable path
1439  */
mnt_context_prepare_srcpath(struct libmnt_context * cxt)1440 int mnt_context_prepare_srcpath(struct libmnt_context *cxt)
1441 {
1442 	const char *path = NULL;
1443 	struct libmnt_cache *cache;
1444 	const char *t, *v, *src;
1445 	int rc = 0;
1446 
1447 	assert(cxt);
1448 	assert(cxt->fs);
1449 	assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1450 
1451 	if (!cxt || !cxt->fs)
1452 		return -EINVAL;
1453 
1454 	DBG(CXT, ul_debugobj(cxt, "preparing source path"));
1455 
1456 	src = mnt_fs_get_source(cxt->fs);
1457 
1458 	if (!src && mnt_context_propagation_only(cxt))
1459 		/* mount --make-{shared,private,...} */
1460 		return mnt_fs_set_source(cxt->fs, "none");
1461 
1462 	/* ignore filesystems without source or filesystems
1463 	 * where the source is a quasi-path (//foo/bar)
1464 	 */
1465 	if (!src || mnt_fs_is_netfs(cxt->fs))
1466 		return 0;
1467 
1468 	DBG(CXT, ul_debugobj(cxt, "srcpath '%s'", src));
1469 
1470 	cache = mnt_context_get_cache(cxt);
1471 
1472 	if (!mnt_fs_get_tag(cxt->fs, &t, &v)) {
1473 		/*
1474 		 * Source is TAG (evaluate)
1475 		 */
1476 		if (cache)
1477 			path = mnt_resolve_tag(t, v, cache);
1478 
1479 		rc = path ? mnt_fs_set_source(cxt->fs, path) : -MNT_ERR_NOSOURCE;
1480 
1481 	} else if (cache && !mnt_fs_is_pseudofs(cxt->fs)) {
1482 		/*
1483 		 * Source is PATH (canonicalize)
1484 		 */
1485 		path = mnt_resolve_path(src, cache);
1486 		if (path && strcmp(path, src))
1487 			rc = mnt_fs_set_source(cxt->fs, path);
1488 	 }
1489 
1490 	if (rc) {
1491 		DBG(CXT, ul_debugobj(cxt, "failed to prepare srcpath [rc=%d]", rc));
1492 		return rc;
1493 	}
1494 
1495 	if (!path)
1496 		path = src;
1497 
1498 	if ((cxt->mountflags & (MS_BIND | MS_MOVE | MS_REMOUNT))
1499 	    || mnt_fs_is_pseudofs(cxt->fs)) {
1500 		DBG(CXT, ul_debugobj(cxt, "REMOUNT/BIND/MOVE/pseudo FS source: %s", path));
1501 		return rc;
1502 	}
1503 
1504 	/*
1505 	 * Initialize loop device
1506 	 */
1507 	if (mnt_context_is_loopdev(cxt)) {
1508 		rc = mnt_context_setup_loopdev(cxt);
1509 		if (rc)
1510 			return rc;
1511 	}
1512 
1513 	DBG(CXT, ul_debugobj(cxt, "final srcpath '%s'",
1514 				mnt_fs_get_source(cxt->fs)));
1515 	return 0;
1516 }
1517 
1518 /* create a mountpoint if x-mount.mkdir[=<mode>] specified */
mkdir_target(const char * tgt,struct libmnt_fs * fs)1519 static int mkdir_target(const char *tgt, struct libmnt_fs *fs)
1520 {
1521 	char *mstr = NULL;
1522 	size_t mstr_sz = 0;
1523 	mode_t mode = 0;
1524 	struct stat st;
1525 	int rc;
1526 
1527 	assert(tgt);
1528 	assert(fs);
1529 
1530 	if (mnt_optstr_get_option(fs->user_optstr, "x-mount.mkdir", &mstr, &mstr_sz) != 0)
1531 		return 0;
1532 	if (stat(tgt, &st) == 0)
1533 		return 0;
1534 
1535 	if (mstr && mstr_sz) {
1536 		char *end = NULL;
1537 
1538 		errno = 0;
1539 		mode = strtol(mstr, &end, 8);
1540 
1541 		if (errno || !end || mstr + mstr_sz != end) {
1542 			DBG(CXT, ul_debug("failed to parse mkdir mode '%s'", mstr));
1543 			return -MNT_ERR_MOUNTOPT;
1544 		}
1545 	}
1546 
1547 	if (!mode)
1548 		mode = S_IRWXU |			/* 0755 */
1549 		       S_IRGRP | S_IXGRP |
1550 		       S_IROTH | S_IXOTH;
1551 
1552 	rc = mkdir_p(tgt, mode);
1553 	if (rc)
1554 		DBG(CXT, ul_debug("mkdir %s failed: %m", tgt));
1555 
1556 	return rc;
1557 }
1558 
mnt_context_prepare_target(struct libmnt_context * cxt)1559 int mnt_context_prepare_target(struct libmnt_context *cxt)
1560 {
1561 	const char *tgt;
1562 	struct libmnt_cache *cache;
1563 	int rc = 0;
1564 
1565 	assert(cxt);
1566 	assert(cxt->fs);
1567 	assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1568 
1569 	if (!cxt || !cxt->fs)
1570 		return -EINVAL;
1571 
1572 	DBG(CXT, ul_debugobj(cxt, "preparing target path"));
1573 
1574 	tgt = mnt_fs_get_target(cxt->fs);
1575 	if (!tgt)
1576 		return 0;
1577 
1578 	/* mkdir target */
1579 	if (cxt->action == MNT_ACT_MOUNT
1580 	    && !mnt_context_is_restricted(cxt)
1581 	    && cxt->user_mountflags & MNT_MS_XCOMMENT) {
1582 
1583 		rc = mkdir_target(tgt, cxt->fs);
1584 		if (rc)
1585 			return rc;	/* mkdir or parse error */
1586 	}
1587 
1588 	/* canonicalize the path */
1589 	cache = mnt_context_get_cache(cxt);
1590 	if (cache) {
1591 		char *path = mnt_resolve_path(tgt, cache);
1592 		if (path && strcmp(path, tgt) != 0)
1593 			rc = mnt_fs_set_target(cxt->fs, path);
1594 	}
1595 
1596 	if (rc)
1597 		DBG(CXT, ul_debugobj(cxt, "failed to prepare target '%s'", tgt));
1598 	else
1599 		DBG(CXT, ul_debugobj(cxt, "final target '%s'",
1600 					mnt_fs_get_target(cxt->fs)));
1601 	return 0;
1602 }
1603 
1604 /* Guess type, but not set to cxt->fs, use free() for the result. It's no error
1605  * when we're not able to guess a filesystem type.
1606  */
mnt_context_guess_srcpath_fstype(struct libmnt_context * cxt,char ** type)1607 int mnt_context_guess_srcpath_fstype(struct libmnt_context *cxt, char **type)
1608 {
1609 	int rc = 0;
1610 	const char *dev = mnt_fs_get_srcpath(cxt->fs);
1611 
1612 	*type = NULL;
1613 
1614 	if (!dev)
1615 		goto done;
1616 
1617 	if (access(dev, F_OK) == 0) {
1618 		struct libmnt_cache *cache = mnt_context_get_cache(cxt);
1619 		int ambi = 0;
1620 
1621 		*type = mnt_get_fstype(dev, &ambi, cache);
1622 		if (cache && *type)
1623 			*type = strdup(*type);
1624 		if (ambi)
1625 			rc = -MNT_ERR_AMBIFS;
1626 	} else {
1627 		DBG(CXT, ul_debugobj(cxt, "access(%s) failed [%m]", dev));
1628 		if (strchr(dev, ':') != NULL)
1629 			*type = strdup("nfs");
1630 		else if (!strncmp(dev, "//", 2))
1631 			*type = strdup("cifs");
1632 	}
1633 
1634 done:
1635 	return rc;
1636 }
1637 
1638 /*
1639  * It's usually no error when we're not able to detect the filesystem type -- we
1640  * will try to use the types from /{etc,proc}/filesystems.
1641  */
mnt_context_guess_fstype(struct libmnt_context * cxt)1642 int mnt_context_guess_fstype(struct libmnt_context *cxt)
1643 {
1644 	char *type;
1645 	int rc = 0;
1646 
1647 	assert(cxt);
1648 	assert(cxt->fs);
1649 	assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1650 
1651 	if (!cxt || !cxt->fs)
1652 		return -EINVAL;
1653 
1654 	if ((cxt->mountflags & (MS_BIND | MS_MOVE))
1655 	    || mnt_context_propagation_only(cxt))
1656 		goto none;
1657 
1658 	type = (char *) mnt_fs_get_fstype(cxt->fs);
1659 	if (type && !strcmp(type, "auto")) {
1660 		mnt_fs_set_fstype(cxt->fs, NULL);
1661 		type = NULL;
1662 	}
1663 
1664 	if (type)
1665 		goto done;
1666 	if (cxt->flags & MS_REMOUNT)
1667 		goto none;
1668 	if (cxt->fstype_pattern)
1669 		goto done;
1670 
1671 	rc = mnt_context_guess_srcpath_fstype(cxt, &type);
1672 	if (rc == 0 && type)
1673 		__mnt_fs_set_fstype_ptr(cxt->fs, type);
1674 	else
1675 		free(type);
1676 done:
1677 	DBG(CXT, ul_debugobj(cxt, "FS type: %s [rc=%d]",
1678 				mnt_fs_get_fstype(cxt->fs), rc));
1679 	return rc;
1680 none:
1681 	return mnt_fs_set_fstype(cxt->fs, "none");
1682 }
1683 
1684 /*
1685  * The default is to use fstype from cxt->fs, this could be overwritten by
1686  * @type. The @act is MNT_ACT_{MOUNT,UMOUNT}.
1687  *
1688  * Returns: 0 on success or negative number in case of error. Note that success
1689  * does not mean that there is any usable helper, you have to check cxt->helper.
1690  */
mnt_context_prepare_helper(struct libmnt_context * cxt,const char * name,const char * type)1691 int mnt_context_prepare_helper(struct libmnt_context *cxt, const char *name,
1692 				const char *type)
1693 {
1694 	char search_path[] = FS_SEARCH_PATH;		/* from config.h */
1695 	char *p = NULL, *path;
1696 
1697 	assert(cxt);
1698 	assert(cxt->fs);
1699 	assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1700 
1701 	if (!type)
1702 		type = mnt_fs_get_fstype(cxt->fs);
1703 
1704 	if (type && strchr(type, ','))
1705 		return 0;			/* type is fstype pattern */
1706 
1707 	if (mnt_context_is_nohelpers(cxt)
1708 	    || !type
1709 	    || !strcmp(type, "none")
1710 	    || strstr(type, "/..")		/* don't try to smuggle path */
1711 	    || mnt_fs_is_swaparea(cxt->fs))
1712 		return 0;
1713 
1714 	path = strtok_r(search_path, ":", &p);
1715 	while (path) {
1716 		char helper[PATH_MAX];
1717 		struct stat st;
1718 		int rc;
1719 
1720 		rc = snprintf(helper, sizeof(helper), "%s/%s.%s",
1721 						path, name, type);
1722 		path = strtok_r(NULL, ":", &p);
1723 
1724 		if (rc < 0 || (size_t) rc >= sizeof(helper))
1725 			continue;
1726 
1727 		rc = stat(helper, &st);
1728 		if (rc == -1 && errno == ENOENT && strchr(type, '.')) {
1729 			/* If type ends with ".subtype" try without it */
1730 			char *hs = strrchr(helper, '.');
1731 			if (hs)
1732 				*hs = '\0';
1733 			rc = stat(helper, &st);
1734 		}
1735 
1736 		DBG(CXT, ul_debugobj(cxt, "%-25s ... %s", helper,
1737 					rc ? "not found" : "found"));
1738 		if (rc)
1739 			continue;
1740 
1741 		free(cxt->helper);
1742 		cxt->helper = strdup(helper);
1743 		if (!cxt->helper)
1744 			return -ENOMEM;
1745 		return 0;
1746 	}
1747 
1748 	return 0;
1749 }
1750 
mnt_context_merge_mflags(struct libmnt_context * cxt)1751 int mnt_context_merge_mflags(struct libmnt_context *cxt)
1752 {
1753 	unsigned long fl = 0;
1754 	int rc;
1755 
1756 	assert(cxt);
1757 
1758 	DBG(CXT, ul_debugobj(cxt, "merging mount flags"));
1759 
1760 	rc = mnt_context_get_mflags(cxt, &fl);
1761 	if (rc)
1762 		return rc;
1763 	cxt->mountflags = fl;
1764 
1765 	fl = 0;
1766 	rc = mnt_context_get_user_mflags(cxt, &fl);
1767 	if (rc)
1768 		return rc;
1769 	cxt->user_mountflags = fl;
1770 
1771 	DBG(CXT, ul_debugobj(cxt, "final flags: VFS=%08lx user=%08lx",
1772 			cxt->mountflags, cxt->user_mountflags));
1773 
1774 	cxt->flags |= MNT_FL_MOUNTFLAGS_MERGED;
1775 	return 0;
1776 }
1777 
1778 /*
1779  * Prepare /etc/mtab or /run/mount/utab
1780  */
mnt_context_prepare_update(struct libmnt_context * cxt)1781 int mnt_context_prepare_update(struct libmnt_context *cxt)
1782 {
1783 	int rc;
1784 	const char *target;
1785 
1786 	assert(cxt);
1787 	assert(cxt->fs);
1788 	assert(cxt->action);
1789 	assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1790 
1791 	DBG(CXT, ul_debugobj(cxt, "prepare update"));
1792 
1793 	if (mnt_context_propagation_only(cxt)) {
1794 		DBG(CXT, ul_debugobj(cxt, "skip update: only MS_PROPAGATION"));
1795 		return 0;
1796 	}
1797 
1798 	target = mnt_fs_get_target(cxt->fs);
1799 
1800 	if (cxt->action == MNT_ACT_UMOUNT && target && !strcmp(target, "/"))
1801 		/* Don't try to touch mtab if umounting root FS */
1802 		mnt_context_disable_mtab(cxt, TRUE);
1803 
1804 	if (mnt_context_is_nomtab(cxt)) {
1805 		DBG(CXT, ul_debugobj(cxt, "skip update: NOMTAB flag"));
1806 		return 0;
1807 	}
1808 	if (!mnt_context_get_writable_tabpath(cxt)) {
1809 		DBG(CXT, ul_debugobj(cxt, "skip update: no writable destination"));
1810 		return 0;
1811 	}
1812 	/* 0 = success, 1 = not called yet */
1813 	if (cxt->syscall_status != 1 && cxt->syscall_status != 0) {
1814 		DBG(CXT, ul_debugobj(cxt,
1815 				"skip update: syscall failed [status=%d]",
1816 				cxt->syscall_status));
1817 		return 0;
1818 	}
1819 
1820 	if (!cxt->update) {
1821 		const char *name = mnt_context_get_writable_tabpath(cxt);
1822 
1823 		if (cxt->action == MNT_ACT_UMOUNT && is_file_empty(name)) {
1824 			DBG(CXT, ul_debugobj(cxt,
1825 				"skip update: umount, no table"));
1826 			return 0;
1827 		}
1828 
1829 		cxt->update = mnt_new_update();
1830 		if (!cxt->update)
1831 			return -ENOMEM;
1832 
1833 		mnt_update_set_filename(cxt->update, name,
1834 				!mnt_context_mtab_writable(cxt));
1835 	}
1836 
1837 	if (cxt->action == MNT_ACT_UMOUNT)
1838 		rc = mnt_update_set_fs(cxt->update, cxt->mountflags,
1839 					mnt_context_get_target(cxt), NULL);
1840 	else
1841 		rc = mnt_update_set_fs(cxt->update, cxt->mountflags,
1842 					NULL, cxt->fs);
1843 
1844 	return rc < 0 ? rc : 0;
1845 }
1846 
mnt_context_update_tabs(struct libmnt_context * cxt)1847 int mnt_context_update_tabs(struct libmnt_context *cxt)
1848 {
1849 	unsigned long fl;
1850 
1851 	assert(cxt);
1852 
1853 	if (mnt_context_is_nomtab(cxt)) {
1854 		DBG(CXT, ul_debugobj(cxt, "don't update: NOMTAB flag"));
1855 		return 0;
1856 	}
1857 	if (!cxt->update || !mnt_update_is_ready(cxt->update)) {
1858 		DBG(CXT, ul_debugobj(cxt, "don't update: no update prepared"));
1859 		return 0;
1860 	}
1861 
1862 	/* check utab update when external helper executed */
1863 	if (mnt_context_helper_executed(cxt)
1864 	    && mnt_context_get_helper_status(cxt) == 0
1865 	    && mnt_context_utab_writable(cxt)) {
1866 
1867 		if (mnt_update_already_done(cxt->update, cxt->lock)) {
1868 			DBG(CXT, ul_debugobj(cxt, "don't update: error evaluate or already updated"));
1869 			return 0;
1870 		}
1871 	} else if (cxt->helper) {
1872 		DBG(CXT, ul_debugobj(cxt, "don't update: external helper"));
1873 		return 0;
1874 	}
1875 
1876 	if (cxt->syscall_status != 0
1877 	    && !(mnt_context_helper_executed(cxt) &&
1878 		 mnt_context_get_helper_status(cxt) == 0)) {
1879 
1880 		DBG(CXT, ul_debugobj(cxt, "don't update: syscall/helper failed/not called"));
1881 		return 0;
1882 	}
1883 
1884 	fl = mnt_update_get_mflags(cxt->update);
1885 	if ((cxt->mountflags & MS_RDONLY) != (fl & MS_RDONLY))
1886 		/*
1887 		 * fix MS_RDONLY in options
1888 		 */
1889 		mnt_update_force_rdonly(cxt->update,
1890 				cxt->mountflags & MS_RDONLY);
1891 
1892 	return mnt_update_table(cxt->update, cxt->lock);
1893 }
1894 
apply_table(struct libmnt_context * cxt,struct libmnt_table * tb,int direction)1895 static int apply_table(struct libmnt_context *cxt, struct libmnt_table *tb,
1896 		     int direction)
1897 {
1898 	struct libmnt_fs *fs = NULL;
1899 	const char *src = NULL, *tgt = NULL;
1900 	int rc;
1901 
1902 	assert(cxt);
1903 	assert(cxt->fs);
1904 
1905 	if (!cxt->fs)
1906 		return -EINVAL;
1907 
1908 	src = mnt_fs_get_source(cxt->fs);
1909 	tgt = mnt_fs_get_target(cxt->fs);
1910 
1911 	if (tgt && src)
1912 		fs = mnt_table_find_pair(tb, src, tgt, direction);
1913 	else {
1914 		if (src)
1915 			fs = mnt_table_find_source(tb, src, direction);
1916 		else if (tgt)
1917 			fs = mnt_table_find_target(tb, tgt, direction);
1918 
1919 		if (!fs && mnt_context_is_swapmatch(cxt)) {
1920 			/* swap source and target (if @src is not LABEL/UUID),
1921 			 * for example in
1922 			 *
1923 			 *	mount /foo/bar
1924 			 *
1925 			 * the path could be a mountpoint as well as a source (for
1926 			 * example bind mount, symlink to a device, ...).
1927 			 */
1928 			if (src && !mnt_fs_get_tag(cxt->fs, NULL, NULL))
1929 				fs = mnt_table_find_target(tb, src, direction);
1930 			if (!fs && tgt)
1931 				fs = mnt_table_find_source(tb, tgt, direction);
1932 		}
1933 	}
1934 
1935 	if (!fs)
1936 		return -MNT_ERR_NOFSTAB;	/* not found */
1937 
1938 	DBG(CXT, ul_debugobj(cxt, "apply entry:"));
1939 	DBG(CXT, mnt_fs_print_debug(fs, stderr));
1940 
1941 	/* copy from tab to our FS description
1942 	 */
1943 	rc = mnt_fs_set_source(cxt->fs, mnt_fs_get_source(fs));
1944 	if (!rc)
1945 		rc = mnt_fs_set_target(cxt->fs, mnt_fs_get_target(fs));
1946 
1947 	if (!rc && !mnt_fs_get_fstype(cxt->fs))
1948 		rc = mnt_fs_set_fstype(cxt->fs, mnt_fs_get_fstype(fs));
1949 
1950 	if (rc)
1951 		return rc;
1952 
1953 	if (cxt->optsmode & MNT_OMODE_IGNORE)
1954 		;
1955 	else if (cxt->optsmode & MNT_OMODE_REPLACE)
1956 		rc = mnt_fs_set_options(cxt->fs, mnt_fs_get_options(fs));
1957 
1958 	else if (cxt->optsmode & MNT_OMODE_APPEND)
1959 		rc = mnt_fs_append_options(cxt->fs, mnt_fs_get_options(fs));
1960 
1961 	else if (cxt->optsmode & MNT_OMODE_PREPEND)
1962 		rc = mnt_fs_prepend_options(cxt->fs, mnt_fs_get_options(fs));
1963 
1964 	if (!rc)
1965 		cxt->flags |= MNT_FL_TAB_APPLIED;
1966 	return rc;
1967 }
1968 
1969 /**
1970  * mnt_context_apply_fstab:
1971  * @cxt: mount context
1972  *
1973  * This function is optional.
1974  *
1975  * Returns: 0 on success, negative number in case of error.
1976  */
mnt_context_apply_fstab(struct libmnt_context * cxt)1977 int mnt_context_apply_fstab(struct libmnt_context *cxt)
1978 {
1979 	int rc = -1;
1980 	struct libmnt_table *tab = NULL;
1981 	const char *src = NULL, *tgt = NULL;
1982 
1983 	assert(cxt);
1984 	assert(cxt->fs);
1985 
1986 	if (!cxt)
1987 		return -EINVAL;
1988 
1989 	if (mnt_context_tab_applied(cxt))	/* already applied */
1990 		return 0;
1991 
1992 	if (mnt_context_is_restricted(cxt)) {
1993 		DBG(CXT, ul_debugobj(cxt, "force fstab usage for non-root users!"));
1994 		cxt->optsmode = MNT_OMODE_USER;
1995 	} else if (cxt->optsmode == 0) {
1996 		DBG(CXT, ul_debugobj(cxt, "use default optsmode"));
1997 		cxt->optsmode = MNT_OMODE_AUTO;
1998 	} else if (cxt->optsmode & MNT_OMODE_NOTAB) {
1999 		cxt->optsmode &= ~MNT_OMODE_FSTAB;
2000 		cxt->optsmode &= ~MNT_OMODE_MTAB;
2001 		cxt->optsmode &= ~MNT_OMODE_FORCE;
2002 	}
2003 
2004 	if (cxt->fs) {
2005 		src = mnt_fs_get_source(cxt->fs);
2006 		tgt = mnt_fs_get_target(cxt->fs);
2007 	}
2008 
2009 	DBG(CXT, ul_debugobj(cxt, "OPTSMODE: ignore=%d, append=%d, prepend=%d, "
2010 				  "replace=%d, force=%d, fstab=%d, mtab=%d",
2011 				  cxt->optsmode & MNT_OMODE_IGNORE ? 1 : 0,
2012 				  cxt->optsmode & MNT_OMODE_APPEND ? 1 : 0,
2013 				  cxt->optsmode & MNT_OMODE_PREPEND ? 1 : 0,
2014 				  cxt->optsmode & MNT_OMODE_REPLACE ? 1 : 0,
2015 				  cxt->optsmode & MNT_OMODE_FORCE ? 1 : 0,
2016 				  cxt->optsmode & MNT_OMODE_FSTAB ? 1 : 0,
2017 				  cxt->optsmode & MNT_OMODE_MTAB ? 1 : 0));
2018 
2019 	/* fstab is not required if source and target are specified */
2020 	if (src && tgt && !(cxt->optsmode & MNT_OMODE_FORCE)) {
2021 		DBG(CXT, ul_debugobj(cxt, "fstab not required -- skip"));
2022 		return 0;
2023 	}
2024 
2025 	if (!src && tgt
2026 	    && !(cxt->optsmode & MNT_OMODE_FSTAB)
2027 	    && !(cxt->optsmode & MNT_OMODE_MTAB)) {
2028 		DBG(CXT, ul_debugobj(cxt, "only target; fstab/mtab not required "
2029 					  "-- skip, probably MS_PROPAGATION"));
2030 		return 0;
2031 	}
2032 
2033 	DBG(CXT, ul_debugobj(cxt,
2034 		"trying to apply fstab (src=%s, target=%s)", src, tgt));
2035 
2036 	/* let's initialize cxt->fs */
2037 	ignore_result( mnt_context_get_fs(cxt) );
2038 
2039 	/* try fstab */
2040 	if (cxt->optsmode & MNT_OMODE_FSTAB) {
2041 		rc = mnt_context_get_fstab(cxt, &tab);
2042 		if (!rc)
2043 			rc = apply_table(cxt, tab, MNT_ITER_FORWARD);
2044 	}
2045 
2046 	/* try mtab */
2047 	if (rc < 0 && (cxt->optsmode & MNT_OMODE_MTAB)) {
2048 		DBG(CXT, ul_debugobj(cxt, "trying to apply from mtab"));
2049 		rc = mnt_context_get_mtab(cxt, &tab);
2050 		if (!rc)
2051 			rc = apply_table(cxt, tab, MNT_ITER_BACKWARD);
2052 	}
2053 	if (rc) {
2054 		DBG(CXT, ul_debugobj(cxt, "failed to find entry in fstab/mtab [rc=%d]: %m", rc));
2055 
2056 		/* force to "not found in fstab/mtab" error, the details why
2057 		 * not found are not so important and may be misinterpreted by
2058 		 * applications... */
2059 		rc = -MNT_ERR_NOFSTAB;
2060 	}
2061 	return rc;
2062 }
2063 
2064 /**
2065  * mnt_context_tab_applied:
2066  * @cxt: mount context
2067  *
2068  * Returns: 1 if fstab (or mtab) has been applied to the context, or 0.
2069  */
mnt_context_tab_applied(struct libmnt_context * cxt)2070 int mnt_context_tab_applied(struct libmnt_context *cxt)
2071 {
2072 	assert(cxt);
2073 	return cxt->flags & MNT_FL_TAB_APPLIED;
2074 }
2075 
2076 /*
2077  * This is not a public function!
2078  *
2079  * Returns 1 if *only propagation flags* change is requested.
2080  */
mnt_context_propagation_only(struct libmnt_context * cxt)2081 int mnt_context_propagation_only(struct libmnt_context *cxt)
2082 {
2083 	assert(cxt);
2084 	assert(cxt->fs);
2085 
2086 	if (cxt->action != MNT_ACT_MOUNT)
2087 		return 0;
2088 
2089 	/* has to be called after context_mount.c: fix_opts() */
2090 	assert((cxt->flags & MNT_FL_MOUNTOPTS_FIXED));
2091 
2092 	/* all propagation mounts are in cxt->addmount */
2093 	return !list_empty(&cxt->addmounts)
2094 	       && (cxt->mountflags == 0 || cxt->mountflags == MS_SILENT)
2095 	       && cxt->fs
2096 	       && (!cxt->fs->fstype || strcmp(cxt->fs->fstype, "none") == 0)
2097 	       && (!cxt->fs->source || strcmp(cxt->fs->source, "none") == 0);
2098 }
2099 
2100 /**
2101  * mnt_context_get_status:
2102  * @cxt: mount context
2103  *
2104  * Global libmount status.
2105  *
2106  * The real exit code of the mount.type helper has to be tested by
2107  * mnt_context_get_helper_status(). The mnt_context_get_status() only informs
2108  * that exec() has been successful.
2109  *
2110  * Returns: 1 if mount.type or mount(2) syscall has been successfully called.
2111  */
mnt_context_get_status(struct libmnt_context * cxt)2112 int mnt_context_get_status(struct libmnt_context *cxt)
2113 {
2114 	assert(cxt);
2115 	return !cxt->syscall_status || !cxt->helper_exec_status;
2116 }
2117 
2118 /**
2119  * mnt_context_helper_executed:
2120  * @cxt: mount context
2121  *
2122  * Returns: 1 if mount.type helper has been executed, or 0.
2123  */
mnt_context_helper_executed(struct libmnt_context * cxt)2124 int mnt_context_helper_executed(struct libmnt_context *cxt)
2125 {
2126 	assert(cxt);
2127 	return cxt->helper_exec_status != 1;
2128 }
2129 
2130 /**
2131  * mnt_context_get_helper_status:
2132  * @cxt: mount context
2133  *
2134  * Return: mount.type helper exit status, result is reliable only if
2135  *         mnt_context_helper_executed() returns 1.
2136  */
mnt_context_get_helper_status(struct libmnt_context * cxt)2137 int mnt_context_get_helper_status(struct libmnt_context *cxt)
2138 {
2139 	assert(cxt);
2140 	return cxt->helper_status;
2141 }
2142 
2143 /**
2144  * mnt_context_syscall_called:
2145  * @cxt: mount context
2146  *
2147  * Returns: 1 if mount(2) syscall has been called, or 0.
2148  */
mnt_context_syscall_called(struct libmnt_context * cxt)2149 int mnt_context_syscall_called(struct libmnt_context *cxt)
2150 {
2151 	assert(cxt);
2152 	return cxt->syscall_status != 1;
2153 }
2154 
2155 /**
2156  * mnt_context_get_syscall_errno:
2157  * @cxt: mount context
2158  *
2159  * The result from this function is reliable only if
2160  * mnt_context_syscall_called() returns 1.
2161  *
2162  * Returns: mount(2) errno if the syscall failed or 0.
2163  */
mnt_context_get_syscall_errno(struct libmnt_context * cxt)2164 int mnt_context_get_syscall_errno(struct libmnt_context *cxt)
2165 {
2166 	assert(cxt);
2167 	if (cxt->syscall_status < 0)
2168 		return -cxt->syscall_status;
2169 	return 0;
2170 }
2171 
2172 /**
2173  * mnt_context_set_syscall_status:
2174  * @cxt: mount context
2175  * @status: mount(2) status
2176  *
2177  * The @status should be 0 on success, or negative number on error (-errno).
2178  *
2179  * This function should only be used if the [u]mount(2) syscall is NOT called by
2180  * libmount code.
2181  *
2182  * Returns: 0 or negative number in case of error.
2183  */
mnt_context_set_syscall_status(struct libmnt_context * cxt,int status)2184 int mnt_context_set_syscall_status(struct libmnt_context *cxt, int status)
2185 {
2186 	assert(cxt);
2187 	if (!cxt)
2188 		return -EINVAL;
2189 
2190 	DBG(CXT, ul_debugobj(cxt, "syscall status set to: %d", status));
2191 	cxt->syscall_status = status;
2192 	return 0;
2193 }
2194 
2195 /**
2196  * mnt_context_strerror
2197  * @cxt: context
2198  * @buf: buffer
2199  * @bufsiz: size of the buffer
2200  *
2201  * Not implemented yet.
2202  *
2203  * Returns: 0 or negative number in case of error.
2204  */
mnt_context_strerror(struct libmnt_context * cxt,char * buf,size_t bufsiz)2205 int mnt_context_strerror(struct libmnt_context *cxt __attribute__((__unused__)),
2206 			 char *buf __attribute__((__unused__)),
2207 			 size_t bufsiz __attribute__((__unused__)))
2208 {
2209 	/* TODO: based on cxt->syscall_errno or cxt->helper_status */
2210 	return 0;
2211 }
2212 
2213 /**
2214  * mnt_context_init_helper
2215  * @cxt: mount context
2216  * @action: MNT_ACT_{UMOUNT,MOUNT}
2217  * @flags: not used now
2218  *
2219  * This function informs libmount that used from [u]mount.type helper.
2220  *
2221  * The function also calls mnt_context_disable_helpers() to avoid recursive
2222  * mount.type helpers calling. It you really want to call another
2223  * mount.type helper from your helper, then you have to explicitly enable this
2224  * feature by:
2225  *
2226  *	 mnt_context_disable_helpers(cxt, FALSE);
2227  *
2228  * Returns: 0 on success, negative number in case of error.
2229  */
mnt_context_init_helper(struct libmnt_context * cxt,int action,int flags)2230 int mnt_context_init_helper(struct libmnt_context *cxt, int action,
2231 			    int flags __attribute__((__unused__)))
2232 {
2233 	int rc;
2234 
2235 	assert(cxt);
2236 
2237 	rc = mnt_context_disable_helpers(cxt, TRUE);
2238 	if (!rc)
2239 		rc = set_flag(cxt, MNT_FL_HELPER, 1);
2240 	if (!rc)
2241 		cxt->action = action;
2242 
2243 	DBG(CXT, ul_debugobj(cxt, "initialized for [u]mount.<type> helper [rc=%d]", rc));
2244 	return rc;
2245 }
2246 
2247 /**
2248  * mnt_context_helper_setopt:
2249  * @cxt: context
2250  * @c: getopt() result
2251  * @arg: getopt() optarg
2252  *
2253  * This function applies the [u]mount.type command line option (for example parsed
2254  * by getopt or getopt_long) to @cxt. All unknown options are ignored and
2255  * then 1 is returned.
2256  *
2257  * Returns: negative number on error, 1 if @c is unknown option, 0 on success.
2258  */
mnt_context_helper_setopt(struct libmnt_context * cxt,int c,char * arg)2259 int mnt_context_helper_setopt(struct libmnt_context *cxt, int c, char *arg)
2260 {
2261 	if (cxt) {
2262 		switch(cxt->action) {
2263 		case MNT_ACT_MOUNT:
2264 			return mnt_context_mount_setopt(cxt, c, arg);
2265 		case MNT_ACT_UMOUNT:
2266 			return mnt_context_umount_setopt(cxt, c, arg);
2267 		}
2268 	}
2269 	return -EINVAL;
2270 }
2271 
2272 /**
2273  * mnt_context_is_fs_mounted:
2274  * @cxt: context
2275  * @fs: filesystem
2276  * @mounted: returns 1 for mounted and 0 for non-mounted filesystems
2277  *
2278  * Please, read the mnt_table_is_fs_mounted() description!
2279  *
2280  * Returns: 0 on success and negative number in case of error.
2281  */
mnt_context_is_fs_mounted(struct libmnt_context * cxt,struct libmnt_fs * fs,int * mounted)2282 int mnt_context_is_fs_mounted(struct libmnt_context *cxt,
2283 			      struct libmnt_fs *fs, int *mounted)
2284 {
2285 	struct libmnt_table *mtab;
2286 	int rc;
2287 
2288 	assert(cxt);
2289 	if (!cxt || !fs || !mounted)
2290 		return -EINVAL;
2291 
2292 	rc = mnt_context_get_mtab(cxt, &mtab);
2293 	if (rc)
2294 		return rc;
2295 
2296 	*mounted = mnt_table_is_fs_mounted(mtab, fs);
2297 	return 0;
2298 }
2299 
mnt_context_add_child(struct libmnt_context * cxt,pid_t pid)2300 static int mnt_context_add_child(struct libmnt_context *cxt, pid_t pid)
2301 {
2302 	pid_t *pids;
2303 
2304 	assert(cxt);
2305 	if (!cxt)
2306 		return -EINVAL;
2307 
2308 	pids = realloc(cxt->children, sizeof(pid_t) * cxt->nchildren + 1);
2309 	if (!pids)
2310 		return -ENOMEM;
2311 
2312 	DBG(CXT, ul_debugobj(cxt, "add new child %d", pid));
2313 	cxt->children = pids;
2314 	cxt->children[cxt->nchildren++] = pid;
2315 
2316 	return 0;
2317 }
2318 
mnt_fork_context(struct libmnt_context * cxt)2319 int mnt_fork_context(struct libmnt_context *cxt)
2320 {
2321 	int rc = 0;
2322 	pid_t pid;
2323 
2324 	assert(cxt);
2325 	if (!mnt_context_is_parent(cxt))
2326 		return -EINVAL;
2327 
2328 	DBG(CXT, ul_debugobj(cxt, "forking context"));
2329 
2330 	DBG_FLUSH;
2331 
2332 	pid = fork();
2333 
2334 	switch (pid) {
2335 	case -1: /* error */
2336 		DBG(CXT, ul_debugobj(cxt, "fork failed %m"));
2337 		return -errno;
2338 
2339 	case 0: /* child */
2340 		cxt->pid = getpid();
2341 		mnt_context_enable_fork(cxt, FALSE);
2342 		DBG(CXT, ul_debugobj(cxt, "child created"));
2343 		break;
2344 
2345 	default:
2346 		rc = mnt_context_add_child(cxt, pid);
2347 		break;
2348 	}
2349 
2350 	return rc;
2351 }
2352 
mnt_context_wait_for_children(struct libmnt_context * cxt,int * nchildren,int * nerrs)2353 int mnt_context_wait_for_children(struct libmnt_context *cxt,
2354 				  int *nchildren, int *nerrs)
2355 {
2356 	int i;
2357 
2358 	assert(cxt);
2359 	if (!cxt)
2360 		return -EINVAL;
2361 
2362 	assert(mnt_context_is_parent(cxt));
2363 
2364 	for (i = 0; i < cxt->nchildren; i++) {
2365 		pid_t pid = cxt->children[i];
2366 		int rc = 0, ret = 0;
2367 
2368 		if (!pid)
2369 			continue;
2370 		do {
2371 			DBG(CXT, ul_debugobj(cxt,
2372 					"waiting for child (%d/%d): %d",
2373 					i + 1, cxt->nchildren, pid));
2374 			errno = 0;
2375 			rc = waitpid(pid, &ret, 0);
2376 
2377 		} while (rc == -1 && errno == EINTR);
2378 
2379 		if (nchildren)
2380 			(*nchildren)++;
2381 
2382 		if (rc != -1 && nerrs) {
2383 			if (WIFEXITED(ret))
2384 				(*nerrs) += WEXITSTATUS(ret) == 0 ? 0 : 1;
2385 			else
2386 				(*nerrs)++;
2387 		}
2388 		cxt->children[i] = 0;
2389 	}
2390 
2391 	cxt->nchildren = 0;
2392 	free(cxt->children);
2393 	cxt->children = NULL;
2394 	return 0;
2395 }
2396 
2397 
2398 
2399 #ifdef TEST_PROGRAM
2400 
2401 struct libmnt_lock *lock;
2402 
lock_fallback(void)2403 static void lock_fallback(void)
2404 {
2405 	if (lock)
2406 		mnt_unlock_file(lock);
2407 }
2408 
test_mount(struct libmnt_test * ts,int argc,char * argv[])2409 int test_mount(struct libmnt_test *ts, int argc, char *argv[])
2410 {
2411 	int idx = 1, rc = 0;
2412 	struct libmnt_context *cxt;
2413 
2414 	if (argc < 2)
2415 		return -EINVAL;
2416 
2417 	cxt = mnt_new_context();
2418 	if (!cxt)
2419 		return -ENOMEM;
2420 
2421 	if (!strcmp(argv[idx], "-o")) {
2422 		mnt_context_set_options(cxt, argv[idx + 1]);
2423 		idx += 2;
2424 	}
2425 	if (!strcmp(argv[idx], "-t")) {
2426 		/* TODO: use mnt_context_set_fstype_pattern() */
2427 		mnt_context_set_fstype(cxt, argv[idx + 1]);
2428 		idx += 2;
2429 	}
2430 
2431 	if (argc == idx + 1)
2432 		/* mount <mountpont>|<device> */
2433 		mnt_context_set_target(cxt, argv[idx++]);
2434 
2435 	else if (argc == idx + 2) {
2436 		/* mount <device> <mountpoint> */
2437 		mnt_context_set_source(cxt, argv[idx++]);
2438 		mnt_context_set_target(cxt, argv[idx++]);
2439 	}
2440 
2441 	/* this is unnecessary! -- libmount is able to internally
2442 	 * create and manage the lock
2443 	 */
2444 	lock = mnt_context_get_lock(cxt);
2445 	if (lock)
2446 		atexit(lock_fallback);
2447 
2448 	rc = mnt_context_mount(cxt);
2449 	if (rc)
2450 		warn("failed to mount");
2451 	else
2452 		printf("successfully mounted\n");
2453 
2454 	lock = NULL;	/* because we use atexit lock_fallback */
2455 	mnt_free_context(cxt);
2456 	return rc;
2457 }
2458 
test_umount(struct libmnt_test * ts,int argc,char * argv[])2459 int test_umount(struct libmnt_test *ts, int argc, char *argv[])
2460 {
2461 	int idx = 1, rc = 0;
2462 	struct libmnt_context *cxt;
2463 
2464 	if (argc < 2)
2465 		return -EINVAL;
2466 
2467 	cxt = mnt_new_context();
2468 	if (!cxt)
2469 		return -ENOMEM;
2470 
2471 	if (!strcmp(argv[idx], "-t")) {
2472 		mnt_context_set_fstype(cxt, argv[idx + 1]);
2473 		idx += 2;
2474 	}
2475 
2476 	if (!strcmp(argv[idx], "-f")) {
2477 		mnt_context_enable_force(cxt, TRUE);
2478 		idx++;
2479 	}
2480 
2481 	if (!strcmp(argv[idx], "-l")) {
2482 		mnt_context_enable_lazy(cxt, TRUE);
2483 		idx++;
2484 	}
2485 
2486 	if (!strcmp(argv[idx], "-r")) {
2487 		mnt_context_enable_rdonly_umount(cxt, TRUE);
2488 		idx++;
2489 	}
2490 
2491 	if (argc == idx + 1) {
2492 		/* mount <mountpont>|<device> */
2493 		mnt_context_set_target(cxt, argv[idx++]);
2494 	} else {
2495 		rc = -EINVAL;
2496 		goto err;
2497 	}
2498 
2499 	lock = mnt_context_get_lock(cxt);
2500 	if (lock)
2501 		atexit(lock_fallback);
2502 
2503 	rc = mnt_context_umount(cxt);
2504 	if (rc)
2505 		printf("failed to umount\n");
2506 	else
2507 		printf("successfully umounted\n");
2508 err:
2509 	lock = NULL;	/* because we use atexit lock_fallback */
2510 	mnt_free_context(cxt);
2511 	return rc;
2512 }
2513 
test_flags(struct libmnt_test * ts,int argc,char * argv[])2514 int test_flags(struct libmnt_test *ts, int argc, char *argv[])
2515 {
2516 	int idx = 1, rc = 0;
2517 	struct libmnt_context *cxt;
2518 	const char *opt = NULL;
2519 	unsigned long flags = 0;
2520 
2521 	if (argc < 2)
2522 		return -EINVAL;
2523 
2524 	cxt = mnt_new_context();
2525 	if (!cxt)
2526 		return -ENOMEM;
2527 
2528 	if (!strcmp(argv[idx], "-o")) {
2529 		mnt_context_set_options(cxt, argv[idx + 1]);
2530 		idx += 2;
2531 	}
2532 
2533 	if (argc == idx + 1)
2534 		/* mount <mountpont>|<device> */
2535 		mnt_context_set_target(cxt, argv[idx++]);
2536 
2537 	rc = mnt_context_prepare_mount(cxt);
2538 	if (rc)
2539 		printf("failed to prepare mount %s\n", strerror(-rc));
2540 
2541 	opt = mnt_fs_get_options(cxt->fs);
2542 	if (opt)
2543 		fprintf(stdout, "options: %s\n", opt);
2544 
2545 	mnt_context_get_mflags(cxt, &flags);
2546 	fprintf(stdout, "flags: %08lx\n", flags);
2547 
2548 	mnt_free_context(cxt);
2549 	return rc;
2550 }
2551 
test_mountall(struct libmnt_test * ts,int argc,char * argv[])2552 int test_mountall(struct libmnt_test *ts, int argc, char *argv[])
2553 {
2554 	struct libmnt_context *cxt;
2555 	struct libmnt_iter *itr;
2556 	struct libmnt_fs *fs;
2557 	int mntrc, ignored, idx = 1;
2558 
2559 	cxt = mnt_new_context();
2560 	itr = mnt_new_iter(MNT_ITER_FORWARD);
2561 
2562 	if (!cxt || !itr)
2563 		return -ENOMEM;
2564 
2565 	if (argc > 2) {
2566 		if (argv[idx] && !strcmp(argv[idx], "-O")) {
2567 			mnt_context_set_options_pattern(cxt, argv[idx + 1]);
2568 			idx += 2;
2569 		}
2570 		if (argv[idx] && !strcmp(argv[idx], "-t")) {
2571 			mnt_context_set_fstype_pattern(cxt, argv[idx + 1]);
2572 			idx += 2;
2573 		}
2574 	}
2575 
2576 	while (mnt_context_next_mount(cxt, itr, &fs, &mntrc, &ignored) == 0) {
2577 
2578 		const char *tgt = mnt_fs_get_target(fs);
2579 
2580 		if (ignored == 1)
2581 			printf("%s: ignored: not match\n", tgt);
2582 		else if (ignored == 2)
2583 			printf("%s: ignored: already mounted\n", tgt);
2584 
2585 		else if (!mnt_context_get_status(cxt)) {
2586 			if (mntrc > 0) {
2587 				errno = mntrc;
2588 				warn("%s: mount failed", tgt);
2589 			} else
2590 				warnx("%s: mount failed", tgt);
2591 		} else
2592 			printf("%s: successfully mounted\n", tgt);
2593 	}
2594 
2595 	mnt_free_context(cxt);
2596 	return 0;
2597 }
2598 
main(int argc,char * argv[])2599 int main(int argc, char *argv[])
2600 {
2601 	struct libmnt_test tss[] = {
2602 	{ "--mount",  test_mount,  "[-o <opts>] [-t <type>] <spec>|<src> <target>" },
2603 	{ "--umount", test_umount, "[-t <type>] [-f][-l][-r] <src>|<target>" },
2604 	{ "--mount-all", test_mountall,  "[-O <pattern>] [-t <pattern] mount all filesystems from fstab" },
2605 	{ "--flags", test_flags,   "[-o <opts>] <spec>" },
2606 	{ NULL }};
2607 
2608 	umask(S_IWGRP|S_IWOTH);	/* to be compatible with mount(8) */
2609 
2610 	return mnt_run_test(tss, argc, argv);
2611 }
2612 
2613 #endif /* TEST_PROGRAM */
2614