]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - libmount/src/context.c
55cf75ddd150353e146ef17562f74afacbea9f11
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 * This file is part of libmount from util-linux project.
5 * Copyright (C) 2010-2018 Karel Zak <kzak@redhat.com>
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.
15 * @title: Library high-level context
16 * @short_description: high-level API to mount/umount devices.
20 * struct libmnt_context *cxt = mnt_new_context();
22 * mnt_context_set_options(cxt, "aaa,bbb,ccc=CCC");
23 * mnt_context_set_mflags(cxt, MS_NOATIME|MS_NOEXEC);
24 * mnt_context_set_target(cxt, "/mnt/foo");
26 * if (!mnt_context_mount(cxt))
27 * printf("successfully mounted\n");
28 * mnt_free_context(cxt);
33 * This code is similar to:
35 * mount -o aaa,bbb,ccc=CCC,noatime,noexec /mnt/foo
41 #include "namespace.h"
47 #include "mount-api-utils.h"
53 * Returns: newly allocated mount context
55 struct libmnt_context
*mnt_new_context(void)
57 struct libmnt_context
*cxt
;
60 cxt
= calloc(1, sizeof(*cxt
));
66 mnt_context_reset_status(cxt
);
70 cxt
->ns_cur
= &cxt
->ns_orig
;
72 cxt
->map_linux
= mnt_get_builtin_optmap(MNT_LINUX_MAP
);
73 cxt
->map_userspace
= mnt_get_builtin_optmap(MNT_USERSPACE_MAP
);
75 INIT_LIST_HEAD(&cxt
->hooksets_hooks
);
76 INIT_LIST_HEAD(&cxt
->hooksets_datas
);
78 /* if we're really root and aren't running setuid */
79 cxt
->restricted
= (uid_t
) 0 == ruid
&& !is_privileged_execution() ? 0 : 1;
83 DBG(CXT
, ul_debugobj(cxt
, "----> allocate %s",
84 cxt
->restricted
? "[RESTRICTED]" : ""));
93 * Deallocates context struct.
95 void mnt_free_context(struct libmnt_context
*cxt
)
100 mnt_reset_context(cxt
);
102 free(cxt
->fstype_pattern
);
103 free(cxt
->optstr_pattern
);
104 free(cxt
->tgt_prefix
);
106 mnt_unref_table(cxt
->fstab
);
107 mnt_unref_cache(cxt
->cache
);
108 mnt_unref_fs(cxt
->fs
);
110 mnt_unref_optlist(cxt
->optlist_saved
);
111 mnt_unref_optlist(cxt
->optlist
);
113 mnt_unref_lock(cxt
->lock
);
114 mnt_free_update(cxt
->update
);
116 mnt_context_set_target_ns(cxt
, NULL
);
120 DBG(CXT
, ul_debugobj(cxt
, "free"));
126 * @cxt: mount context
128 * Resets all information in the context that is directly related to
129 * the latest mount (spec, source, target, mount options, ...).
131 * The match patterns, target namespace, prefix, cached fstab, cached canonicalized
132 * paths and tags and [e]uid are not reset. You have to use
134 * mnt_context_set_fstab(cxt, NULL);
135 * mnt_context_set_cache(cxt, NULL);
136 * mnt_context_set_fstype_pattern(cxt, NULL);
137 * mnt_context_set_options_pattern(cxt, NULL);
138 * mnt_context_set_target_ns(cxt, NULL);
140 * to reset this stuff.
142 * Returns: 0 on success, negative number in case of error.
144 int mnt_reset_context(struct libmnt_context
*cxt
)
151 DBG(CXT
, ul_debugobj(cxt
, "<---- reset [status=%d] ---->",
152 mnt_context_get_status(cxt
)));
156 mnt_unref_fs(cxt
->fs
);
157 mnt_unref_table(cxt
->mountinfo
);
158 mnt_unref_table(cxt
->utab
);
159 mnt_unref_optlist(cxt
->optlist
);
164 cxt
->mountinfo
= NULL
;
168 cxt
->mountdata
= NULL
;
169 cxt
->flags
= MNT_FL_DEFAULT
;
171 cxt
->has_selinux_opt
= 0;
173 cxt
->map_linux
= mnt_get_builtin_optmap(MNT_LINUX_MAP
);
174 cxt
->map_userspace
= mnt_get_builtin_optmap(MNT_USERSPACE_MAP
);
176 mnt_context_reset_status(cxt
);
177 mnt_context_deinit_hooksets(cxt
);
179 if (cxt
->table_fltrcb
)
180 mnt_context_set_tabfilter(cxt
, NULL
, NULL
);
182 /* restore non-resettable flags */
183 cxt
->flags
|= (fl
& MNT_FL_NOMTAB
);
184 cxt
->flags
|= (fl
& MNT_FL_FAKE
);
185 cxt
->flags
|= (fl
& MNT_FL_SLOPPY
);
186 cxt
->flags
|= (fl
& MNT_FL_VERBOSE
);
187 cxt
->flags
|= (fl
& MNT_FL_NOHELPERS
);
188 cxt
->flags
|= (fl
& MNT_FL_LOOPDEL
);
189 cxt
->flags
|= (fl
& MNT_FL_LAZY
);
190 cxt
->flags
|= (fl
& MNT_FL_FORK
);
191 cxt
->flags
|= (fl
& MNT_FL_FORCE
);
192 cxt
->flags
|= (fl
& MNT_FL_NOCANONICALIZE
);
193 cxt
->flags
|= (fl
& MNT_FL_RDONLY_UMOUNT
);
194 cxt
->flags
|= (fl
& MNT_FL_RWONLY_MOUNT
);
195 cxt
->flags
|= (fl
& MNT_FL_NOSWAPMATCH
);
196 cxt
->flags
|= (fl
& MNT_FL_TABPATHS_CHECKED
);
198 mnt_context_apply_template(cxt
);
204 * Saves the current context setting (mount options, etc) to make it usable after
205 * mnt_reset_context() or by mnt_context_apply_template(). This is usable for
206 * example for mnt_context_next_mount() where for the next mount operation we
207 * need to restore to the original context setting.
209 * Returns: 0 on success, negative number in case of error.
211 int mnt_context_save_template(struct libmnt_context
*cxt
)
216 DBG(CXT
, ul_debugobj(cxt
, "saving template"));
218 /* reset old saved data */
219 mnt_unref_optlist(cxt
->optlist_saved
);
220 cxt
->optlist_saved
= NULL
;
223 cxt
->optlist_saved
= mnt_copy_optlist(cxt
->optlist
);
229 * Restores context FS setting from previously saved template (see
230 * mnt_context_save_template()).
232 * Returns: 0 on success, negative number in case of error.
234 int mnt_context_apply_template(struct libmnt_context
*cxt
)
240 mnt_unref_optlist(cxt
->optlist
);
244 if (cxt
->optlist_saved
) {
245 DBG(CXT
, ul_debugobj(cxt
, "restoring template"));
246 cxt
->optlist
= mnt_copy_optlist(cxt
->optlist_saved
);
252 int mnt_context_has_template(struct libmnt_context
*cxt
)
254 return cxt
&& cxt
->optlist_saved
? 1 : 0;
257 struct libmnt_context
*mnt_copy_context(struct libmnt_context
*o
)
259 struct libmnt_context
*n
;
261 n
= mnt_new_context();
265 DBG(CXT
, ul_debugobj(n
, "<---- clone ---->"));
270 n
->fs
= mnt_copy_fs(NULL
, o
->fs
);
275 n
->mountinfo
= o
->mountinfo
;
276 mnt_ref_table(n
->mountinfo
);
279 mnt_ref_table(n
->utab
);
281 if (strdup_between_structs(n
, o
, tgt_prefix
))
283 if (strdup_between_structs(n
, o
, helper
))
286 n
->map_linux
= o
->map_linux
;
287 n
->map_userspace
= o
->map_userspace
;
289 mnt_context_reset_status(n
);
291 n
->table_fltrcb
= o
->table_fltrcb
;
292 n
->table_fltrcb_data
= o
->table_fltrcb_data
;
294 n
->noautofs
= o
->noautofs
;
295 n
->has_selinux_opt
= o
->has_selinux_opt
;
304 * mnt_context_reset_status:
307 * Resets mount(2) and mount.type statuses, so mnt_context_do_mount() or
308 * mnt_context_do_umount() could be again called with the same settings.
310 * BE CAREFUL -- after this soft reset the libmount will NOT parse mount
311 * options, evaluate permissions or apply stuff from fstab.
313 * Returns: 0 on success, negative number in case of error.
315 int mnt_context_reset_status(struct libmnt_context
*cxt
)
320 mnt_context_syscall_reset_status(cxt
);
322 cxt
->syscall_status
= 1; /* means not called yet */
323 cxt
->helper_exec_status
= 1;
324 cxt
->helper_status
= 0;
328 static int context_init_paths(struct libmnt_context
*cxt
, int writable
)
330 struct libmnt_ns
*ns_old
;
334 if (!cxt
->utab_path
) {
335 cxt
->utab_path
= mnt_get_utab_path();
336 DBG(CXT
, ul_debugobj(cxt
, "utab path initialized to: %s", cxt
->utab_path
));
340 return 0; /* only paths wanted */
341 if (mnt_context_is_nomtab(cxt
))
342 return 0; /* write mode overridden by mount -n */
343 if (cxt
->flags
& MNT_FL_TABPATHS_CHECKED
)
346 DBG(CXT
, ul_debugobj(cxt
, "checking for writable tab files"));
348 ns_old
= mnt_context_switch_target_ns(cxt
);
350 return -MNT_ERR_NAMESPACE
;
352 mnt_has_regular_utab(&cxt
->utab_path
, &cxt
->utab_writable
);
354 if (!mnt_context_switch_ns(cxt
, ns_old
))
355 return -MNT_ERR_NAMESPACE
;
357 cxt
->flags
|= MNT_FL_TABPATHS_CHECKED
;
361 int mnt_context_utab_writable(struct libmnt_context
*cxt
)
365 context_init_paths(cxt
, 1);
366 return cxt
->utab_writable
== 1;
369 const char *mnt_context_get_writable_tabpath(struct libmnt_context
*cxt
)
373 return mnt_context_utab_writable(cxt
) ? cxt
->utab_path
: NULL
;
377 static int set_flag(struct libmnt_context
*cxt
, int flag
, int enable
)
382 DBG(CXT
, ul_debugobj(cxt
, "enabling flag %04x", flag
));
385 DBG(CXT
, ul_debugobj(cxt
, "disabling flag %04x", flag
));
392 * mnt_context_is_restricted:
393 * @cxt: mount context
395 * Returns: 0 for an unrestricted mount (user is root), or 1 for non-root mounts
397 int mnt_context_is_restricted(struct libmnt_context
*cxt
)
399 return cxt
->restricted
;
403 * mnt_context_force_unrestricted:
404 * @cxt: mount context
406 * This function is DANGEROURS as it disables all security policies in libmount.
407 * Don't use if not sure. It removes "restricted" flag from the context, so
408 * libmount will use the current context as for root user.
410 * This function is designed for case you have no any suid permissions, so you
411 * can depend on kernel.
413 * Returns: 0 on success, negative number in case of error.
417 int mnt_context_force_unrestricted(struct libmnt_context
*cxt
)
419 if (mnt_context_is_restricted(cxt
)) {
420 DBG(CXT
, ul_debugobj(cxt
, "force UNRESTRICTED"));
428 * mnt_context_set_optsmode
429 * @cxt: mount context
430 * @mode: MNT_OMODE_* flags
432 * Controls how to use mount optionssource and target paths from fstab/mountinfo.
434 * @MNT_OMODE_IGNORE: ignore fstab options
436 * @MNT_OMODE_APPEND: append fstab options to existing options
438 * @MNT_OMODE_PREPEND: prepend fstab options to existing options
440 * @MNT_OMODE_REPLACE: replace existing options with options from fstab
442 * @MNT_OMODE_FORCE: always read fstab (although source and target are defined)
444 * @MNT_OMODE_FSTAB: read from fstab
446 * @MNT_OMODE_MTAB: read from mountinfo if fstab not enabled or failed
448 * @MNT_OMODE_NOTAB: do not read fstab/mountinfoat all
450 * @MNT_OMODE_AUTO: default mode (MNT_OMODE_PREPEND | MNT_OMODE_FSTAB | MNT_OMODE_MTAB)
452 * @MNT_OMODE_USER: default for non-root users (MNT_OMODE_REPLACE | MNT_OMODE_FORCE | MNT_OMODE_FSTAB)
456 * - MNT_OMODE_USER is always used if mount context is in restricted mode
457 * - MNT_OMODE_AUTO is used if nothing else is defined
458 * - the flags are evaluated in this order: MNT_OMODE_NOTAB, MNT_OMODE_FORCE,
459 * MNT_OMODE_FSTAB, MNT_OMODE_MTAB and then the mount options from fstab/mountinfo
460 * are set according to MNT_OMODE_{IGNORE,APPEND,PREPEND,REPLACE}
462 * Returns: 0 on success, negative number in case of error.
464 int mnt_context_set_optsmode(struct libmnt_context
*cxt
, int mode
)
468 cxt
->optsmode
= mode
;
473 * mnt_context_get_optsmode
474 * @cxt: mount context
476 * Returns: MNT_OMODE_* mask or zero.
479 int mnt_context_get_optsmode(struct libmnt_context
*cxt
)
481 return cxt
->optsmode
;
485 * mnt_context_disable_canonicalize:
486 * @cxt: mount context
487 * @disable: TRUE or FALSE
489 * Enable/disable paths canonicalization and tags evaluation. The libmount context
490 * canonicalizes paths when searching in fstab and when preparing source and target paths
491 * for mount(2) syscall.
493 * This function has an effect on the private (within context) fstab instance only
494 * (see mnt_context_set_fstab()). If you want to use an external fstab then you
495 * need to manage your private struct libmnt_cache (see mnt_table_set_cache(fstab,
498 * Returns: 0 on success, negative number in case of error.
500 int mnt_context_disable_canonicalize(struct libmnt_context
*cxt
, int disable
)
502 return set_flag(cxt
, MNT_FL_NOCANONICALIZE
, disable
);
506 * mnt_context_is_nocanonicalize:
507 * @cxt: mount context
509 * Returns: 1 if no-canonicalize mode (on [u]mount command line) is enabled or 0.
511 int mnt_context_is_nocanonicalize(struct libmnt_context
*cxt
)
513 return cxt
->flags
& MNT_FL_NOCANONICALIZE
? 1 : 0;
518 * Returns 1 if "x-mount.nocanonicalize[=<type>]" userspace mount option is
519 * specified. The optional arguments 'type' should be "source" or "target".
521 int mnt_context_is_xnocanonicalize(
522 struct libmnt_context
*cxt
,
525 struct libmnt_optlist
*ol
;
526 struct libmnt_opt
*opt
;
532 ol
= mnt_context_get_optlist(cxt
);
535 opt
= mnt_optlist_get_named(ol
, "X-mount.nocanonicalize",
539 arg
= mnt_opt_get_value(opt
);
542 return strcmp(arg
, type
) == 0;
546 * mnt_context_enable_lazy:
547 * @cxt: mount context
548 * @enable: TRUE or FALSE
550 * Enable/disable lazy umount (see umount(8) man page, option -l).
552 * Returns: 0 on success, negative number in case of error.
554 int mnt_context_enable_lazy(struct libmnt_context
*cxt
, int enable
)
556 return set_flag(cxt
, MNT_FL_LAZY
, enable
);
560 * mnt_context_is_lazy:
561 * @cxt: mount context
563 * Returns: 1 if lazy umount is enabled or 0
565 int mnt_context_is_lazy(struct libmnt_context
*cxt
)
567 return cxt
->flags
& MNT_FL_LAZY
? 1 : 0;
571 * mnt_context_enable_onlyonce:
572 * @cxt: mount context
573 * @enable: TRUE or FALSE
575 * Enable/disable only-once mount (check if FS is not already mounted).
577 * Returns: 0 on success, negative number in case of error.
579 int mnt_context_enable_onlyonce(struct libmnt_context
*cxt
, int enable
)
581 return set_flag(cxt
, MNT_FL_ONLYONCE
, enable
);
585 * mnt_context_is_onlyonce:
586 * @cxt: mount context
588 * Returns: 1 if only-once mount is enabled or 0
590 int mnt_context_is_onlyonce(struct libmnt_context
*cxt
)
592 return cxt
->flags
& MNT_FL_ONLYONCE
? 1 : 0;
596 * mnt_context_enable_fork:
597 * @cxt: mount context
598 * @enable: TRUE or FALSE
600 * Enable/disable fork(2) call in mnt_context_next_mount() (see mount(8) man
603 * Returns: 0 on success, negative number in case of error.
605 int mnt_context_enable_fork(struct libmnt_context
*cxt
, int enable
)
607 return set_flag(cxt
, MNT_FL_FORK
, enable
);
611 * mnt_context_is_fork:
612 * @cxt: mount context
614 * Returns: 1 if fork (mount -F) is enabled or 0
616 int mnt_context_is_fork(struct libmnt_context
*cxt
)
618 return cxt
->flags
& MNT_FL_FORK
? 1 : 0;
622 * mnt_context_is_parent:
623 * @cxt: mount context
625 * Return: 1 if mount -F enabled and the current context is parent, or 0
627 int mnt_context_is_parent(struct libmnt_context
*cxt
)
629 return mnt_context_is_fork(cxt
) && cxt
->pid
== 0;
633 * mnt_context_is_child:
634 * @cxt: mount context
636 * Return: 1 f the current context is child, or 0
638 int mnt_context_is_child(struct libmnt_context
*cxt
)
640 /* See mnt_fork_context(), the for fork flag is always disabled
641 * for children to avoid recursive forking.
643 return !mnt_context_is_fork(cxt
) && cxt
->pid
;
647 * mnt_context_enable_rdonly_umount:
648 * @cxt: mount context
649 * @enable: TRUE or FALSE
651 * Enable/disable read-only remount on failed umount(2)
652 * (see umount(8) man page, option -r).
654 * Returns: 0 on success, negative number in case of error.
656 int mnt_context_enable_rdonly_umount(struct libmnt_context
*cxt
, int enable
)
658 return set_flag(cxt
, MNT_FL_RDONLY_UMOUNT
, enable
);
662 * mnt_context_is_rdonly_umount
663 * @cxt: mount context
665 * See also mnt_context_enable_rdonly_umount() and umount(8) man page,
668 * Returns: 1 if read-only remount failed umount(2) is enables or 0
670 int mnt_context_is_rdonly_umount(struct libmnt_context
*cxt
)
672 return cxt
->flags
& MNT_FL_RDONLY_UMOUNT
? 1 : 0;
676 * mnt_context_enable_rwonly_mount:
677 * @cxt: mount context
678 * @enable: TRUE or FALSE
680 * Force read-write mount; if enabled libmount will never try MS_RDONLY
681 * after failed mount(2) EROFS. (See mount(8) man page, option -w).
685 * Returns: 0 on success, negative number in case of error.
687 int mnt_context_enable_rwonly_mount(struct libmnt_context
*cxt
, int enable
)
689 return set_flag(cxt
, MNT_FL_RWONLY_MOUNT
, enable
);
693 * mnt_context_is_rwonly_mount
694 * @cxt: mount context
696 * See also mnt_context_enable_rwonly_mount() and mount(8) man page,
701 * Returns: 1 if only read-write mount is allowed.
703 int mnt_context_is_rwonly_mount(struct libmnt_context
*cxt
)
705 return cxt
->flags
& MNT_FL_RWONLY_MOUNT
? 1 : 0;
709 * mnt_context_forced_rdonly:
710 * @cxt: mount context
712 * See also mnt_context_enable_rwonly_mount().
716 * Returns: 1 if mounted read-only on write-protected device.
718 int mnt_context_forced_rdonly(struct libmnt_context
*cxt
)
720 return cxt
->flags
& MNT_FL_FORCED_RDONLY
? 1 : 0;
724 * mnt_context_disable_helpers:
725 * @cxt: mount context
726 * @disable: TRUE or FALSE
728 * Enable/disable /sbin/[u]mount.* helpers (see mount(8) man page, option -i).
730 * Returns: 0 on success, negative number in case of error.
732 int mnt_context_disable_helpers(struct libmnt_context
*cxt
, int disable
)
734 return set_flag(cxt
, MNT_FL_NOHELPERS
, disable
);
738 * mnt_context_is_nohelpers
739 * @cxt: mount context
741 * Returns: 1 if helpers are disabled (mount -i) or 0
743 int mnt_context_is_nohelpers(struct libmnt_context
*cxt
)
745 return cxt
->flags
& MNT_FL_NOHELPERS
? 1 : 0;
750 * mnt_context_enable_sloppy:
751 * @cxt: mount context
752 * @enable: TRUE or FALSE
754 * Set/unset sloppy mounting (see mount(8) man page, option -s).
756 * Returns: 0 on success, negative number in case of error.
758 int mnt_context_enable_sloppy(struct libmnt_context
*cxt
, int enable
)
760 return set_flag(cxt
, MNT_FL_SLOPPY
, enable
);
764 * mnt_context_is_sloppy:
765 * @cxt: mount context
767 * Returns: 1 if sloppy flag is enabled or 0
769 int mnt_context_is_sloppy(struct libmnt_context
*cxt
)
771 return cxt
->flags
& MNT_FL_SLOPPY
? 1 : 0;
775 * mnt_context_enable_fake:
776 * @cxt: mount context
777 * @enable: TRUE or FALSE
779 * Enable/disable fake mounting (see mount(8) man page, option -f).
781 * Returns: 0 on success, negative number in case of error.
783 int mnt_context_enable_fake(struct libmnt_context
*cxt
, int enable
)
785 return set_flag(cxt
, MNT_FL_FAKE
, enable
);
789 * mnt_context_is_fake:
790 * @cxt: mount context
792 * Returns: 1 if fake flag is enabled or 0
794 int mnt_context_is_fake(struct libmnt_context
*cxt
)
796 return cxt
->flags
& MNT_FL_FAKE
? 1 : 0;
800 * mnt_context_disable_mtab:
801 * @cxt: mount context
802 * @disable: TRUE or FALSE
804 * Disable/enable userspace mount table update (see mount(8) man page,
805 * option -n). Originally /etc/mtab, now /run/mount/utab.
807 * Returns: 0 on success, negative number in case of error.
809 int mnt_context_disable_mtab(struct libmnt_context
*cxt
, int disable
)
811 return set_flag(cxt
, MNT_FL_NOMTAB
, disable
);
815 * mnt_context_is_nomtab:
816 * @cxt: mount context
818 * Returns: 1 if no-mtab is enabled or 0
820 int mnt_context_is_nomtab(struct libmnt_context
*cxt
)
822 return cxt
->flags
& MNT_FL_NOMTAB
? 1 : 0;
826 * mnt_context_disable_swapmatch:
827 * @cxt: mount context
828 * @disable: TRUE or FALSE
830 * Disable/enable swap between source and target for mount(8) if only one path
833 * Returns: 0 on success, negative number in case of error.
835 int mnt_context_disable_swapmatch(struct libmnt_context
*cxt
, int disable
)
837 return set_flag(cxt
, MNT_FL_NOSWAPMATCH
, disable
);
841 * mnt_context_is_swapmatch:
842 * @cxt: mount context
844 * Returns: 1 if swap between source and target is allowed (default is 1) or 0.
846 int mnt_context_is_swapmatch(struct libmnt_context
*cxt
)
848 return cxt
->flags
& MNT_FL_NOSWAPMATCH
? 0 : 1;
852 * mnt_context_enable_force:
853 * @cxt: mount context
854 * @enable: TRUE or FALSE
856 * Enable/disable force umounting (see umount(8) man page, option -f).
858 * Returns: 0 on success, negative number in case of error.
860 int mnt_context_enable_force(struct libmnt_context
*cxt
, int enable
)
862 return set_flag(cxt
, MNT_FL_FORCE
, enable
);
866 * mnt_context_is_force
867 * @cxt: mount context
869 * Returns: 1 if force umounting flag is enabled or 0
871 int mnt_context_is_force(struct libmnt_context
*cxt
)
873 return cxt
->flags
& MNT_FL_FORCE
? 1 : 0;
877 * mnt_context_enable_verbose:
878 * @cxt: mount context
879 * @enable: TRUE or FALSE
881 * Enable/disable verbose output (TODO: not implemented yet)
883 * Returns: 0 on success, negative number in case of error.
885 int mnt_context_enable_verbose(struct libmnt_context
*cxt
, int enable
)
887 return set_flag(cxt
, MNT_FL_VERBOSE
, enable
);
891 * mnt_context_is_verbose
892 * @cxt: mount context
894 * Returns: 1 if verbose flag is enabled or 0
896 int mnt_context_is_verbose(struct libmnt_context
*cxt
)
898 return cxt
->flags
& MNT_FL_VERBOSE
? 1 : 0;
902 * mnt_context_enable_loopdel:
903 * @cxt: mount context
904 * @enable: TRUE or FALSE
906 * Enable/disable the loop delete (destroy) after umount (see umount(8), option -d)
908 * Returns: 0 on success, negative number in case of error.
910 int mnt_context_enable_loopdel(struct libmnt_context
*cxt
, int enable
)
912 return set_flag(cxt
, MNT_FL_LOOPDEL
, enable
);
916 * mnt_context_is_loopdel:
917 * @cxt: mount context
919 * Returns: 1 if loop device should be deleted after umount (umount -d) or 0.
921 int mnt_context_is_loopdel(struct libmnt_context
*cxt
)
923 return cxt
->flags
& MNT_FL_LOOPDEL
? 1 : 0;
927 * mnt_context_set_fs:
928 * @cxt: mount context
929 * @fs: filesystem description
931 * The mount context uses private @fs by default. This function can be used to
932 * overwrite the private @fs with an external instance. This function
933 * increments @fs reference counter (and decrement reference counter of the
936 * The @fs will be modified by mnt_context_set_{source,target,options,fstype}
937 * functions, If the @fs is NULL, then all current FS specific settings (source,
938 * target, etc., exclude spec) are reset.
940 * Returns: 0 on success, negative number in case of error.
942 int mnt_context_set_fs(struct libmnt_context
*cxt
, struct libmnt_fs
*fs
)
950 DBG(CXT
, ul_debugobj(cxt
, "setting new FS"));
954 struct libmnt_optlist
*ol
= mnt_context_get_optlist(cxt
);
961 mnt_optlist_set_optstr(ol
, mnt_fs_get_options(fs
), NULL
);
962 mnt_fs_follow_optlist(fs
, ol
);
967 mnt_fs_follow_optlist(cxt
->fs
, NULL
);
968 mnt_unref_fs(cxt
->fs
);
975 * mnt_context_get_fs:
976 * @cxt: mount context
978 * The FS contains the basic description of mountpoint, fs type and so on.
979 * Note that the FS is modified by mnt_context_set_{source,target,options,fstype}
982 * Returns: pointer to FS description or NULL in case of a calloc() error.
984 struct libmnt_fs
*mnt_context_get_fs(struct libmnt_context
*cxt
)
989 struct libmnt_optlist
*ol
= mnt_context_get_optlist(cxt
);
993 cxt
->fs
= mnt_new_fs();
997 mnt_fs_follow_optlist(cxt
->fs
, ol
);
1003 * mnt_context_get_fs_userdata:
1004 * @cxt: mount context
1006 * Returns: pointer to userdata or NULL.
1008 void *mnt_context_get_fs_userdata(struct libmnt_context
*cxt
)
1010 return cxt
->fs
? mnt_fs_get_userdata(cxt
->fs
) : NULL
;
1014 * mnt_context_get_fstab_userdata:
1015 * @cxt: mount context
1017 * Returns: pointer to userdata or NULL.
1019 void *mnt_context_get_fstab_userdata(struct libmnt_context
*cxt
)
1021 return cxt
->fstab
? mnt_table_get_userdata(cxt
->fstab
) : NULL
;
1025 * mnt_context_get_mtab_userdata:
1026 * @cxt: mount context
1028 * The file /etc/mtab is no more used, @context points always to mountinfo
1029 * (/proc/self/mountinfo). The function uses "mtab" in the name for backward
1030 * compatibility only.
1032 * Returns: pointer to userdata or NULL.
1034 void *mnt_context_get_mtab_userdata(struct libmnt_context
*cxt
)
1036 return cxt
->mountinfo
? mnt_table_get_userdata(cxt
->mountinfo
) : NULL
;
1040 * mnt_context_set_source:
1041 * @cxt: mount context
1042 * @source: mount source (device, directory, UUID, LABEL, ...)
1044 * Note that libmount does not interpret "nofail" (MNT_MS_NOFAIL)
1045 * mount option. The real return code is always returned, when
1046 * the device does not exist then it's usually MNT_ERR_NOSOURCE
1047 * from libmount or ENOENT, ENOTDIR, ENOTBLK, ENXIO from mount(2).
1049 * Returns: 0 on success, negative number in case of error.
1051 int mnt_context_set_source(struct libmnt_context
*cxt
, const char *source
)
1053 return mnt_fs_set_source(mnt_context_get_fs(cxt
), source
);
1057 * mnt_context_get_source:
1058 * @cxt: mount context
1060 * Returns: returns pointer or NULL in case of error or if not set.
1062 const char *mnt_context_get_source(struct libmnt_context
*cxt
)
1064 return mnt_fs_get_source(mnt_context_get_fs(cxt
));
1068 * mnt_context_set_target:
1069 * @cxt: mount context
1070 * @target: mountpoint
1072 * Returns: 0 on success, negative number in case of error.
1074 int mnt_context_set_target(struct libmnt_context
*cxt
, const char *target
)
1076 return mnt_fs_set_target(mnt_context_get_fs(cxt
), target
);
1080 * mnt_context_get_target:
1081 * @cxt: mount context
1083 * Returns: returns pointer or NULL in case of error or if not set.
1085 const char *mnt_context_get_target(struct libmnt_context
*cxt
)
1087 return mnt_fs_get_target(mnt_context_get_fs(cxt
));
1091 * mnt_context_set_target_prefix:
1092 * @cxt: mount context
1093 * @path: mountpoint prefix
1095 * Returns: 0 on success, negative number in case of error.
1097 int mnt_context_set_target_prefix(struct libmnt_context
*cxt
, const char *path
)
1108 free(cxt
->tgt_prefix
);
1109 cxt
->tgt_prefix
= p
;
1115 * mnt_context_get_target_prefix:
1116 * @cxt: mount context
1118 * Returns: returns pointer or NULL in case of error or if not set.
1120 const char *mnt_context_get_target_prefix(struct libmnt_context
*cxt
)
1122 return cxt
? cxt
->tgt_prefix
: NULL
;
1127 * mnt_context_set_fstype:
1128 * @cxt: mount context
1129 * @fstype: filesystem type
1131 * Note that the @fstype has to be a FS type. For patterns with
1132 * comma-separated list of filesystems or for the "nofs" notation, use
1133 * mnt_context_set_fstype_pattern().
1135 * Returns: 0 on success, negative number in case of error.
1137 int mnt_context_set_fstype(struct libmnt_context
*cxt
, const char *fstype
)
1139 return mnt_fs_set_fstype(mnt_context_get_fs(cxt
), fstype
);
1143 * mnt_context_get_fstype:
1144 * @cxt: mount context
1146 * Returns: pointer or NULL in case of error or if not set.
1148 const char *mnt_context_get_fstype(struct libmnt_context
*cxt
)
1150 return mnt_fs_get_fstype(mnt_context_get_fs(cxt
));
1153 struct libmnt_optlist
*mnt_context_get_optlist(struct libmnt_context
*cxt
)
1157 if (!cxt
->optlist
) {
1158 cxt
->optlist
= mnt_new_optlist();
1161 if (mnt_optlist_register_map(cxt
->optlist
, cxt
->map_linux
))
1163 if (mnt_optlist_register_map(cxt
->optlist
, cxt
->map_userspace
))
1167 return cxt
->optlist
;
1169 mnt_unref_optlist(cxt
->optlist
);
1174 * mnt_context_set_options:
1175 * @cxt: mount context
1176 * @optstr: comma delimited mount options
1178 * Please note that MS_MOVE cannot be specified as a "string". The move operation
1179 * cannot be specified in fstab.
1181 * Returns: 0 on success, negative number in case of error.
1183 int mnt_context_set_options(struct libmnt_context
*cxt
, const char *optstr
)
1185 struct libmnt_optlist
*ls
= mnt_context_get_optlist(cxt
);
1189 return mnt_optlist_set_optstr(ls
, optstr
, NULL
);
1193 * mnt_context_append_options:
1194 * @cxt: mount context
1195 * @optstr: comma delimited mount options
1197 * Returns: 0 on success, negative number in case of error.
1199 int mnt_context_append_options(struct libmnt_context
*cxt
, const char *optstr
)
1201 struct libmnt_optlist
*ls
= mnt_context_get_optlist(cxt
);
1205 return mnt_optlist_append_optstr(ls
, optstr
, NULL
);
1209 * mnt_context_get_options:
1210 * @cxt: mount context
1212 * This function returns mount options set by mnt_context_set_options(),
1213 * mnt_context_append_options() or mnt_context_set_mflags();
1215 * Before v2.39 this function ignored options specified by flags (see
1216 * mnt_context_set_mflags()) before mnt_context_prepare_mount() call. Now this
1217 * function always returns all mount options.
1219 * Returns: pointer or NULL
1221 const char *mnt_context_get_options(struct libmnt_context
*cxt
)
1223 const char *str
= NULL
;
1225 if (cxt
->optlist
&& !mnt_optlist_is_empty(cxt
->optlist
))
1226 mnt_optlist_get_optstr(cxt
->optlist
, &str
, NULL
, 0);
1231 * mnt_context_set_fstype_pattern:
1232 * @cxt: mount context
1233 * @pattern: FS name pattern (or NULL to reset the current setting)
1235 * See mount(8), option -t.
1237 * Returns: 0 on success, negative number in case of error.
1239 int mnt_context_set_fstype_pattern(struct libmnt_context
*cxt
, const char *pattern
)
1246 p
= strdup(pattern
);
1250 free(cxt
->fstype_pattern
);
1251 cxt
->fstype_pattern
= p
;
1256 * mnt_context_set_options_pattern:
1257 * @cxt: mount context
1258 * @pattern: options pattern (or NULL to reset the current setting)
1260 * See mount(8), option -O.
1262 * Returns: 0 on success, negative number in case of error.
1264 int mnt_context_set_options_pattern(struct libmnt_context
*cxt
, const char *pattern
)
1271 p
= strdup(pattern
);
1275 free(cxt
->optstr_pattern
);
1276 cxt
->optstr_pattern
= p
;
1281 * mnt_context_set_fstab:
1282 * @cxt: mount context
1285 * The mount context reads /etc/fstab to the private struct libmnt_table by default.
1286 * This function can be used to overwrite the private fstab with an external
1289 * This function modify the @tb reference counter. This function does not set
1290 * the cache for the @tb. You have to explicitly call mnt_table_set_cache(tb,
1291 * mnt_context_get_cache(cxt));
1293 * The fstab is used read-only and is not modified, it should be possible to
1294 * share the fstab between more mount contexts (TODO: test it.)
1296 * If the @tb argument is NULL, then the current private fstab instance is
1299 * Returns: 0 on success, negative number in case of error.
1301 int mnt_context_set_fstab(struct libmnt_context
*cxt
, struct libmnt_table
*tb
)
1306 mnt_ref_table(tb
); /* new */
1307 mnt_unref_table(cxt
->fstab
); /* old */
1314 * mnt_context_get_fstab:
1315 * @cxt: mount context
1316 * @tb: returns fstab
1318 * See also mnt_table_parse_fstab() for more details about fstab.
1320 * Returns: 0 on success, negative number in case of error.
1322 int mnt_context_get_fstab(struct libmnt_context
*cxt
, struct libmnt_table
**tb
)
1324 struct libmnt_ns
*ns_old
;
1331 cxt
->fstab
= mnt_new_table();
1334 if (cxt
->table_errcb
)
1335 mnt_table_set_parser_errcb(cxt
->fstab
, cxt
->table_errcb
);
1337 ns_old
= mnt_context_switch_target_ns(cxt
);
1339 return -MNT_ERR_NAMESPACE
;
1341 mnt_table_set_cache(cxt
->fstab
, mnt_context_get_cache(cxt
));
1342 rc
= mnt_table_parse_fstab(cxt
->fstab
, NULL
);
1344 if (!mnt_context_switch_ns(cxt
, ns_old
))
1345 return -MNT_ERR_NAMESPACE
;
1356 int mnt_context_get_mountinfo(struct libmnt_context
*cxt
, struct libmnt_table
**tb
)
1359 struct libmnt_ns
*ns_old
= NULL
;
1363 if (!cxt
->mountinfo
) {
1364 ns_old
= mnt_context_switch_target_ns(cxt
);
1366 return -MNT_ERR_NAMESPACE
;
1368 context_init_paths(cxt
, 0);
1370 cxt
->mountinfo
= mnt_new_table();
1371 if (!cxt
->mountinfo
) {
1376 mnt_table_enable_noautofs(cxt
->mountinfo
, cxt
->noautofs
);
1378 if (cxt
->table_errcb
)
1379 mnt_table_set_parser_errcb(cxt
->mountinfo
, cxt
->table_errcb
);
1380 if (cxt
->table_fltrcb
)
1381 mnt_table_set_parser_fltrcb(cxt
->mountinfo
,
1383 cxt
->table_fltrcb_data
);
1385 mnt_table_set_cache(cxt
->mountinfo
, mnt_context_get_cache(cxt
));
1388 /* Read the table; it's empty, because this first mnt_context_get_mountinfo()
1389 * call, or because /proc was not accessible in previous calls */
1390 if (mnt_table_is_empty(cxt
->mountinfo
)) {
1392 ns_old
= mnt_context_switch_target_ns(cxt
);
1394 return -MNT_ERR_NAMESPACE
;
1397 rc
= __mnt_table_parse_mountinfo(cxt
->mountinfo
, NULL
, cxt
->utab
);
1403 *tb
= cxt
->mountinfo
;
1405 DBG(CXT
, ul_debugobj(cxt
, "mountinfo requested [nents=%d]",
1406 mnt_table_get_nents(cxt
->mountinfo
)));
1409 if (ns_old
&& !mnt_context_switch_ns(cxt
, ns_old
))
1410 return -MNT_ERR_NAMESPACE
;
1416 * mnt_context_get_mtab:
1417 * @cxt: mount context
1420 * Parse /proc/self/mountinfo mount table.
1422 * The file /etc/mtab is no more used, @context points always to mountinfo
1423 * (/proc/self/mountinfo). The function uses "mtab" in the name for backward
1424 * compatibility only.
1426 * See also mnt_table_parse_mtab() for more details about mountinfo. The
1427 * result will be deallocated by mnt_free_context(@cxt).
1429 * Returns: 0 on success, negative number in case of error.
1431 int mnt_context_get_mtab(struct libmnt_context
*cxt
, struct libmnt_table
**tb
)
1433 return mnt_context_get_mountinfo(cxt
, tb
);
1437 * Called by mountinfo parser to filter out entries, non-zero means that
1438 * an entry has to be filtered out.
1440 static int mountinfo_filter(struct libmnt_fs
*fs
, void *data
)
1444 if (mnt_fs_streq_target(fs
, data
))
1446 if (mnt_fs_streq_srcpath(fs
, data
))
1452 * The same like mnt_context_get_mountinfo(), but does not read all mountinfo
1453 * file, but only entries relevant for @tgt.
1455 int mnt_context_get_mountinfo_for_target(struct libmnt_context
*cxt
,
1456 struct libmnt_table
**mountinfo
,
1460 struct libmnt_cache
*cache
= NULL
;
1461 char *cn_tgt
= NULL
;
1463 struct libmnt_ns
*ns_old
;
1465 ns_old
= mnt_context_switch_target_ns(cxt
);
1467 return -MNT_ERR_NAMESPACE
;
1469 if (mnt_context_is_nocanonicalize(cxt
))
1470 mnt_context_set_tabfilter(cxt
, mountinfo_filter
, (void *) tgt
);
1472 else if (mnt_safe_stat(tgt
, &st
) == 0 && S_ISDIR(st
.st_mode
)) {
1473 cache
= mnt_context_get_cache(cxt
);
1474 cn_tgt
= mnt_resolve_path(tgt
, cache
);
1476 mnt_context_set_tabfilter(cxt
, mountinfo_filter
, cn_tgt
);
1479 rc
= mnt_context_get_mountinfo(cxt
, mountinfo
);
1480 mnt_context_set_tabfilter(cxt
, NULL
, NULL
);
1482 if (!mnt_context_switch_ns(cxt
, ns_old
))
1483 return -MNT_ERR_NAMESPACE
;
1485 if (cn_tgt
&& !cache
)
1492 * Allows to specify a filter for tab file entries. The filter is called by
1493 * the table parser. Currently used for utab only.
1495 int mnt_context_set_tabfilter(struct libmnt_context
*cxt
,
1496 int (*fltr
)(struct libmnt_fs
*, void *),
1502 cxt
->table_fltrcb
= fltr
;
1503 cxt
->table_fltrcb_data
= data
;
1506 mnt_table_set_parser_fltrcb(cxt
->mountinfo
,
1508 cxt
->table_fltrcb_data
);
1510 DBG(CXT
, ul_debugobj(cxt
, "tabfilter %s", fltr
? "ENABLED!" : "disabled"));
1515 * mnt_context_get_table:
1516 * @cxt: mount context
1517 * @filename: e.g. /proc/self/mountinfo
1518 * @tb: returns the table
1520 * This function allocates a new table and parses the @file. The parser error
1521 * callback and cache for tags and paths is set according to the @cxt setting.
1522 * See also mnt_table_parse_file().
1524 * It's strongly recommended to use the mnt_context_get_mtab() and
1525 * mnt_context_get_fstab() functions for mountinfo and fstab files. This function
1526 * does not care about LIBMOUNT_* env.variables and does not merge userspace
1529 * The result will NOT be deallocated by mnt_free_context(@cxt).
1531 * Returns: 0 on success, negative number in case of error.
1533 int mnt_context_get_table(struct libmnt_context
*cxt
,
1534 const char *filename
, struct libmnt_table
**tb
)
1537 struct libmnt_ns
*ns_old
;
1542 *tb
= mnt_new_table();
1546 if (cxt
->table_errcb
)
1547 mnt_table_set_parser_errcb(*tb
, cxt
->table_errcb
);
1549 ns_old
= mnt_context_switch_target_ns(cxt
);
1551 return -MNT_ERR_NAMESPACE
;
1553 rc
= mnt_table_parse_file(*tb
, filename
);
1556 mnt_unref_table(*tb
);
1560 mnt_table_set_cache(*tb
, mnt_context_get_cache(cxt
));
1563 if (!mnt_context_switch_ns(cxt
, ns_old
))
1564 return -MNT_ERR_NAMESPACE
;
1570 * mnt_context_set_tables_errcb
1571 * @cxt: mount context
1572 * @cb: pointer to callback function
1574 * The error callback is used for all tab files (e.g. mountinfo, fstab)
1575 * parsed within the context.
1577 * See also mnt_context_get_mtab(),
1578 * mnt_context_get_fstab(),
1579 * mnt_table_set_parser_errcb().
1581 * Returns: 0 on success, negative number in case of error.
1583 int mnt_context_set_tables_errcb(struct libmnt_context
*cxt
,
1584 int (*cb
)(struct libmnt_table
*tb
, const char *filename
, int line
))
1590 mnt_table_set_parser_errcb(cxt
->mountinfo
, cb
);
1592 mnt_table_set_parser_errcb(cxt
->fstab
, cb
);
1594 cxt
->table_errcb
= cb
;
1599 * mnt_context_set_cache:
1600 * @cxt: mount context
1601 * @cache: cache instance or NULL
1603 * The mount context maintains a private struct libmnt_cache by default. This
1604 * function can be used to overwrite the private cache with an external instance.
1605 * This function increments cache reference counter.
1607 * If the @cache argument is NULL, then the current cache instance is reset.
1608 * This function apply the cache to fstab and mountinfo instances (if already
1611 * The old cache instance reference counter is de-incremented.
1613 * Returns: 0 on success, negative number in case of error.
1615 int mnt_context_set_cache(struct libmnt_context
*cxt
, struct libmnt_cache
*cache
)
1620 mnt_ref_cache(cache
); /* new */
1621 mnt_unref_cache(cxt
->cache
); /* old */
1626 mnt_table_set_cache(cxt
->mountinfo
, cache
);
1628 mnt_table_set_cache(cxt
->fstab
, cache
);
1634 * mnt_context_get_cache
1635 * @cxt: mount context
1637 * See also mnt_context_set_cache().
1639 * Returns: pointer to cache or NULL if canonicalization is disabled.
1641 struct libmnt_cache
*mnt_context_get_cache(struct libmnt_context
*cxt
)
1643 if (!cxt
|| mnt_context_is_nocanonicalize(cxt
))
1647 struct libmnt_cache
*cache
= mnt_new_cache();
1648 mnt_context_set_cache(cxt
, cache
);
1649 mnt_unref_cache(cache
);
1655 * mnt_context_set_passwd_cb:
1656 * @cxt: mount context
1657 * @get: callback to get password
1658 * @release: callback to release (deallocate) password
1660 * Sets callbacks for encryption password (e.g encrypted loopdev). This
1661 * function is deprecated (encrypted loops are no longer supported).
1663 * Returns: 0 on success, negative number in case of error.
1665 int mnt_context_set_passwd_cb(struct libmnt_context
*cxt
,
1666 char *(*get
)(struct libmnt_context
*),
1667 void (*release
)(struct libmnt_context
*, char *))
1671 cxt
->pwd_get_cb
= get
;
1672 cxt
->pwd_release_cb
= release
;
1677 * mnt_context_get_lock:
1678 * @cxt: mount context
1680 * The libmount applications don't have to care about utab locking, but with a
1681 * small exception: the application has to be able to remove the lock file when
1682 * interrupted by signal or signals have to be ignored when the lock is locked.
1684 * The default behavior is to ignore all signals (except SIGALRM and
1685 * SIGTRAP for utab update) when the lock is locked. If this behavior
1686 * is unacceptable, then use:
1688 * lc = mnt_context_get_lock(cxt);
1690 * mnt_lock_block_signals(lc, FALSE);
1692 * and don't forget to call mnt_unlock_file(lc) before exit.
1694 * Returns: pointer to lock struct or NULL.
1696 struct libmnt_lock
*mnt_context_get_lock(struct libmnt_context
*cxt
)
1699 * DON'T call this function within libmount, it will always allocate
1700 * the lock. The mnt_update_* functions are able to allocate the lock
1701 * only when utab update is really necessary.
1703 if (!cxt
|| mnt_context_is_nomtab(cxt
))
1707 cxt
->lock
= mnt_new_lock(
1708 mnt_context_get_writable_tabpath(cxt
), 0);
1710 mnt_lock_block_signals(cxt
->lock
, TRUE
);
1716 * mnt_context_set_mflags:
1717 * @cxt: mount context
1718 * @flags: mount(2) flags (MS_* flags)
1720 * Sets mount flags (see mount(2) man page).
1722 * Note that order of mount options (strings) and flags matter if you mix
1723 * mnt_context_append_options() and mnt_context_set_mflags().
1725 * Be careful if use MS_REC flag -- this is flags is generic for
1726 * all mask. In this case is better to use options string where
1727 * mount options are independent and nothing is applied to all options.
1729 * Returns: 0 on success, negative number in case of error.
1731 int mnt_context_set_mflags(struct libmnt_context
*cxt
, unsigned long flags
)
1733 struct libmnt_optlist
*ls
= mnt_context_get_optlist(cxt
);
1738 return mnt_optlist_set_flags(ls
, flags
, cxt
->map_linux
);
1742 * mnt_context_get_mflags:
1743 * @cxt: mount context
1744 * @flags: returns MS_* mount flags
1746 * Converts mount options string to MS_* flags and bitwise-OR the result with
1747 * the already defined flags (see mnt_context_set_mflags()).
1749 * Returns: 0 on success, negative number in case of error.
1751 int mnt_context_get_mflags(struct libmnt_context
*cxt
, unsigned long *flags
)
1753 struct libmnt_optlist
*ls
= mnt_context_get_optlist(cxt
);
1758 return mnt_optlist_get_flags(ls
, flags
, cxt
->map_linux
, 0);
1762 * mnt_context_set_user_mflags:
1763 * @cxt: mount context
1764 * @flags: mount(2) flags (MNT_MS_* flags, e.g. MNT_MS_LOOP)
1766 * Sets userspace mount flags.
1768 * See also notes for mnt_context_set_mflags().
1770 * Returns: 0 on success, negative number in case of error.
1772 int mnt_context_set_user_mflags(struct libmnt_context
*cxt
, unsigned long flags
)
1774 struct libmnt_optlist
*ls
= mnt_context_get_optlist(cxt
);
1779 return mnt_optlist_set_flags(ls
, flags
, cxt
->map_userspace
);
1783 * mnt_context_get_user_mflags:
1784 * @cxt: mount context
1785 * @flags: returns mount flags
1787 * Converts mount options string to MNT_MS_* flags and bitwise-OR the result
1788 * with the already defined flags (see mnt_context_set_user_mflags()).
1790 * Returns: 0 on success, negative number in case of error.
1792 int mnt_context_get_user_mflags(struct libmnt_context
*cxt
, unsigned long *flags
)
1794 struct libmnt_optlist
*ls
= mnt_context_get_optlist(cxt
);
1799 return mnt_optlist_get_flags(ls
, flags
, cxt
->map_userspace
, 0);
1803 * mnt_context_set_mountdata:
1804 * @cxt: mount context
1805 * @data: mount(2) data
1807 * The mount context generates mountdata from mount options by default. This
1808 * function can be used to overwrite this behavior, and @data will be used instead
1811 * The libmount does not deallocate the data by mnt_free_context(). Note that
1812 * NULL is also valid mount data.
1814 * Returns: 0 on success, negative number in case of error.
1816 int mnt_context_set_mountdata(struct libmnt_context
*cxt
, void *data
)
1820 cxt
->mountdata
= data
;
1821 cxt
->flags
|= MNT_FL_MOUNTDATA
;
1825 #ifdef USE_LIBMOUNT_MOUNTFD_SUPPORT
1826 int mnt_context_open_tree(struct libmnt_context
*cxt
, const char *path
, unsigned long mflg
)
1828 unsigned long oflg
= OPEN_TREE_CLOEXEC
;
1829 int rc
= 0, fd
= -1;
1831 if (mflg
== (unsigned long) -1) {
1832 rc
= mnt_optlist_get_flags(cxt
->optlist
, &mflg
, cxt
->map_linux
, 0);
1837 path
= mnt_fs_get_target(cxt
->fs
);
1842 /* Classic -oremount,bind,ro is not bind operation, it's just
1843 * VFS flags update only */
1844 if ((mflg
& MS_BIND
) && !(mflg
& MS_REMOUNT
)) {
1845 oflg
|= OPEN_TREE_CLONE
;
1847 /* AT_RECURSIVE is only permitted for OPEN_TREE_CLONE (rbind).
1848 * The other recursive operations are handled by
1849 * mount_setattr() and are independent of open_tree() */
1850 if (mnt_optlist_is_rbind(cxt
->optlist
))
1851 oflg
|= AT_RECURSIVE
;
1854 if (cxt
->force_clone
)
1855 oflg
|= OPEN_TREE_CLONE
;
1857 if (mnt_context_is_xnocanonicalize(cxt
, "source"))
1858 oflg
|= AT_SYMLINK_NOFOLLOW
;
1860 DBG(CXT
, ul_debugobj(cxt
, "open_tree(path=%s%s%s)", path
,
1861 oflg
& OPEN_TREE_CLONE
? " clone" : "",
1862 oflg
& AT_RECURSIVE
? " recursive" : ""));
1863 fd
= open_tree(AT_FDCWD
, path
, oflg
);
1864 mnt_context_syscall_save_status(cxt
, "open_tree", fd
>= 0);
1871 * Translates LABEL/UUID/path to mountable path
1873 int mnt_context_prepare_srcpath(struct libmnt_context
*cxt
)
1875 const char *path
= NULL
;
1876 struct libmnt_cache
*cache
;
1877 const char *t
, *v
, *src
, *type
;
1879 struct libmnt_ns
*ns_old
;
1880 struct libmnt_optlist
*ol
;
1884 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
1886 DBG(CXT
, ul_debugobj(cxt
, "--> preparing source path"));
1888 src
= mnt_fs_get_source(cxt
->fs
);
1890 if (!src
&& mnt_context_propagation_only(cxt
))
1891 /* mount --make-{shared,private,...} */
1892 return mnt_fs_set_source(cxt
->fs
, "none");
1894 /* ignore filesystems without source or filesystems
1895 * where the source is a quasi-path (//foo/bar)
1897 if (!src
|| mnt_fs_is_netfs(cxt
->fs
))
1900 /* ZFS source is always "dataset", not a real path */
1901 type
= mnt_fs_get_fstype(cxt
->fs
);
1902 if (type
&& strcmp(type
, "zfs") == 0)
1905 DBG(CXT
, ul_debugobj(cxt
, "srcpath '%s'", src
));
1907 ns_old
= mnt_context_switch_target_ns(cxt
);
1909 return -MNT_ERR_NAMESPACE
;
1911 cache
= mnt_context_get_cache(cxt
);
1913 if (!mnt_fs_get_tag(cxt
->fs
, &t
, &v
)) {
1915 * Source is TAG (evaluate)
1918 path
= mnt_resolve_tag(t
, v
, cache
);
1920 rc
= path
? mnt_fs_set_source(cxt
->fs
, path
) : -MNT_ERR_NOSOURCE
;
1922 } else if (cache
&& !mnt_fs_is_pseudofs(cxt
->fs
)
1923 && !mnt_context_is_xnocanonicalize(cxt
, "source")) {
1925 * Source is PATH (canonicalize)
1927 path
= mnt_resolve_path(src
, cache
);
1928 if (path
&& strcmp(path
, src
) != 0)
1929 rc
= mnt_fs_set_source(cxt
->fs
, path
);
1933 DBG(CXT
, ul_debugobj(cxt
, "failed to prepare srcpath [rc=%d]", rc
));
1940 ol
= mnt_context_get_optlist(cxt
);
1944 if (mnt_optlist_is_bind(ol
)
1945 || mnt_optlist_is_move(ol
)
1946 || mnt_optlist_is_remount(ol
)
1947 || mnt_fs_is_pseudofs(cxt
->fs
)) {
1948 DBG(CXT
, ul_debugobj(cxt
, "REMOUNT/BIND/MOVE/pseudo FS source: %s", path
));
1952 rc
= mnt_context_call_hooks(cxt
, MNT_STAGE_PREP_SOURCE
);
1956 DBG(CXT
, ul_debugobj(cxt
, "final srcpath '%s'",
1957 mnt_fs_get_source(cxt
->fs
)));
1960 if (!mnt_context_switch_ns(cxt
, ns_old
))
1961 return -MNT_ERR_NAMESPACE
;
1965 /* Guess type, but not set to cxt->fs, always use free() for the result. It's
1966 * no error when we're not able to guess a filesystem type. Note that error
1967 * does not mean that result in @type is NULL.
1969 int mnt_context_guess_srcpath_fstype(struct libmnt_context
*cxt
, char **type
)
1972 struct libmnt_ns
*ns_old
;
1980 dev
= mnt_fs_get_srcpath(cxt
->fs
);
1984 ns_old
= mnt_context_switch_target_ns(cxt
);
1986 return -MNT_ERR_NAMESPACE
;
1988 if (access(dev
, F_OK
) == 0) {
1989 struct libmnt_cache
*cache
= mnt_context_get_cache(cxt
);
1992 *type
= mnt_get_fstype(dev
, &ambi
, cache
);
1994 rc
= -MNT_ERR_AMBIFS
;
1996 if (cache
&& *type
) {
1997 *type
= strdup(*type
);
2002 DBG(CXT
, ul_debugobj(cxt
, "access(%s) failed [%m]", dev
));
2003 if (strchr(dev
, ':') != NULL
) {
2004 *type
= strdup("nfs");
2007 } else if (!strncmp(dev
, "//", 2)) {
2008 *type
= strdup("cifs");
2014 if (!mnt_context_switch_ns(cxt
, ns_old
))
2015 return -MNT_ERR_NAMESPACE
;
2017 if (rc
== 0 && *type
) {
2018 struct libmnt_optlist
*ol
= mnt_context_get_optlist(cxt
);
2019 struct libmnt_opt
*opt
;
2020 const char *allowed
;
2028 opt
= mnt_optlist_get_named(ol
,
2029 "X-mount.auto-fstypes", cxt
->map_userspace
);
2032 && (allowed
= mnt_opt_get_value(opt
))
2033 && !match_fstype(*type
, allowed
)) {
2034 DBG(CXT
, ul_debugobj(cxt
, "%s is not allowed by auto-fstypes=%s",
2038 rc
= -MNT_ERR_NOFSTYPE
;
2046 * It's usually no error when we're not able to detect the filesystem type -- we
2047 * will try to use the types from /{etc,proc}/filesystems.
2049 int mnt_context_guess_fstype(struct libmnt_context
*cxt
)
2051 struct libmnt_optlist
*ol
;
2057 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
2059 DBG(CXT
, ul_debugobj(cxt
, "--> preparing fstype"));
2061 ol
= mnt_context_get_optlist(cxt
);
2065 if (mnt_optlist_is_bind(ol
)
2066 || mnt_optlist_is_move(ol
)
2067 || mnt_context_propagation_only(cxt
))
2070 type
= (char *) mnt_fs_get_fstype(cxt
->fs
);
2071 if (type
&& !strcmp(type
, "auto")) {
2072 mnt_fs_set_fstype(cxt
->fs
, NULL
);
2078 if (mnt_optlist_is_remount(ol
))
2080 if (cxt
->fstype_pattern
)
2083 rc
= mnt_context_guess_srcpath_fstype(cxt
, &type
);
2084 if (rc
== 0 && type
)
2085 __mnt_fs_set_fstype_ptr(cxt
->fs
, type
);
2089 DBG(CXT
, ul_debugobj(cxt
, "FS type: %s [rc=%d]",
2090 mnt_fs_get_fstype(cxt
->fs
), rc
));
2093 return mnt_fs_set_fstype(cxt
->fs
, "none");
2097 * The default is to use fstype from cxt->fs, this could be overwritten by
2098 * @type. The @act is MNT_ACT_{MOUNT,UMOUNT}.
2100 * Returns: 0 on success or negative number in case of error. Note that success
2101 * does not mean that there is any usable helper, you have to check cxt->helper.
2103 int mnt_context_prepare_helper(struct libmnt_context
*cxt
, const char *name
,
2106 char search_path
[] = FS_SEARCH_PATH
; /* from config.h */
2107 char *p
= NULL
, *path
;
2108 struct libmnt_ns
*ns_old
;
2113 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
2115 DBG(CXT
, ul_debugobj(cxt
, "checking for helper"));
2123 type
= mnt_fs_get_fstype(cxt
->fs
);
2125 if (type
&& strchr(type
, ','))
2126 return 0; /* type is fstype pattern */
2128 if (mnt_context_is_nohelpers(cxt
)
2130 || !strcmp(type
, "none")
2131 || strstr(type
, "/..") /* don't try to smuggle path */
2132 || mnt_fs_is_swaparea(cxt
->fs
))
2135 ns_old
= mnt_context_switch_origin_ns(cxt
);
2137 return -MNT_ERR_NAMESPACE
;
2139 /* Ignore errors when search in $PATH and do not modify @rc
2141 path
= strtok_r(search_path
, ":", &p
);
2143 char helper
[PATH_MAX
];
2146 len
= snprintf(helper
, sizeof(helper
), "%s/%s.%s",
2148 path
= strtok_r(NULL
, ":", &p
);
2150 if (len
< 0 || (size_t) len
>= sizeof(helper
))
2153 found
= mnt_is_path(helper
);
2154 if (!found
&& strchr(type
, '.')) {
2155 /* If type ends with ".subtype" try without it */
2156 char *hs
= strrchr(helper
, '.');
2159 found
= mnt_is_path(helper
);
2162 DBG(CXT
, ul_debugobj(cxt
, "%-25s ... %s", helper
,
2163 found
? "found" : "not found"));
2168 rc
= strdup_to_struct_member(cxt
, helper
, helper
);
2172 if (!mnt_context_switch_ns(cxt
, ns_old
))
2173 rc
= -MNT_ERR_NAMESPACE
;
2175 /* make sure helper is not set on error */
2183 /* stop differentiate between options defined by flags and strings */
2184 int mnt_context_merge_mflags(struct libmnt_context
*cxt
)
2186 struct libmnt_optlist
*ls
= mnt_context_get_optlist(cxt
);
2191 /* TODO: optlist returns always flags as merged, so
2192 * MNT_FL_MOUNTFLAGS_MERGED is unnecessary anymore
2194 cxt
->flags
|= MNT_FL_MOUNTFLAGS_MERGED
;
2195 return mnt_optlist_merge_opts(ls
);
2199 * Prepare /run/mount/utab
2201 int mnt_context_prepare_update(struct libmnt_context
*cxt
)
2204 const char *target
, *source
, *name
;
2205 unsigned long flags
= 0;
2206 struct libmnt_optlist
*ol
;
2210 assert(cxt
->action
);
2211 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
2213 DBG(CXT
, ul_debugobj(cxt
, "--> prepare update"));
2215 if (mnt_context_propagation_only(cxt
)) {
2216 DBG(CXT
, ul_debugobj(cxt
, "skip update: only MS_PROPAGATION"));
2220 target
= mnt_fs_get_target(cxt
->fs
);
2221 source
= mnt_fs_get_srcpath(cxt
->fs
);
2223 if (cxt
->action
== MNT_ACT_UMOUNT
&& target
&& !strcmp(target
, "/")) {
2224 DBG(CXT
, ul_debugobj(cxt
, "root umount: setting NOMTAB"));
2225 mnt_context_disable_mtab(cxt
, TRUE
);
2227 if (mnt_context_is_nomtab(cxt
)) {
2228 DBG(CXT
, ul_debugobj(cxt
, "skip update: NOMTAB flag"));
2231 name
= mnt_context_get_writable_tabpath(cxt
);
2233 DBG(CXT
, ul_debugobj(cxt
, "skip update: no writable destination"));
2237 /* 0 = success, 1 = not called yet */
2238 if (cxt
->syscall_status
!= 1 && cxt
->syscall_status
!= 0) {
2239 DBG(CXT
, ul_debugobj(cxt
,
2240 "skip update: syscall failed [status=%d]",
2241 cxt
->syscall_status
));
2245 ol
= mnt_context_get_optlist(cxt
);
2249 if ((cxt
->action
== MNT_ACT_UMOUNT
|| mnt_optlist_is_move(ol
))
2250 && is_file_empty(name
)) {
2251 DBG(CXT
, ul_debugobj(cxt
, "skip update: umount/move, empty table"));
2255 if (mnt_optlist_is_move(ol
) &&
2256 ((target
&& startswithpath(name
, target
))
2257 || (source
&& startswithpath(name
, source
)))) {
2258 DBG(CXT
, ul_debugobj(cxt
, "skip update: utab move"));
2263 cxt
->update
= mnt_new_update();
2267 mnt_update_set_filename(cxt
->update
, name
);
2270 mnt_context_get_mflags(cxt
, &flags
);
2272 if (cxt
->action
== MNT_ACT_UMOUNT
)
2273 rc
= mnt_update_set_fs(cxt
->update
, flags
,
2274 mnt_context_get_target(cxt
), NULL
);
2276 rc
= mnt_update_set_fs(cxt
->update
, flags
,
2279 if (mnt_update_is_ready(cxt
->update
)) {
2280 DBG(CXT
, ul_debugobj(cxt
, "update is ready"));
2281 mnt_update_start(cxt
->update
);
2283 return rc
< 0 ? rc
: 0;
2286 int mnt_context_update_tabs(struct libmnt_context
*cxt
)
2289 struct libmnt_ns
*ns_old
;
2293 if (mnt_context_is_nomtab(cxt
)) {
2294 DBG(CXT
, ul_debugobj(cxt
, "don't update: NOMTAB flag"));
2297 if (!cxt
->update
|| !mnt_update_is_ready(cxt
->update
)) {
2298 DBG(CXT
, ul_debugobj(cxt
, "don't update: no update prepared"));
2302 ns_old
= mnt_context_switch_target_ns(cxt
);
2304 return -MNT_ERR_NAMESPACE
;
2306 /* check utab update when external helper executed */
2307 if (mnt_context_helper_executed(cxt
)
2308 && mnt_context_get_helper_status(cxt
) == 0
2309 && mnt_context_utab_writable(cxt
)) {
2311 if (mnt_update_already_done(cxt
->update
)) {
2312 DBG(CXT
, ul_debugobj(cxt
, "don't update: error evaluate or already updated"));
2315 } else if (cxt
->helper
) {
2316 DBG(CXT
, ul_debugobj(cxt
, "don't update: external helper"));
2320 if (cxt
->syscall_status
!= 0
2321 && !(mnt_context_helper_executed(cxt
) &&
2322 mnt_context_get_helper_status(cxt
) == 0)) {
2324 DBG(CXT
, ul_debugobj(cxt
, "don't update: syscall/helper failed/not called"));
2328 rc
= mnt_update_table(cxt
->update
, cxt
->lock
);
2330 if (rc
== 0 && !mnt_context_within_helper(cxt
))
2331 mnt_update_emit_event(cxt
->update
);
2334 mnt_update_end(cxt
->update
);
2336 if (!mnt_context_switch_ns(cxt
, ns_old
))
2337 return -MNT_ERR_NAMESPACE
;
2341 /* apply @fs to @cxt;
2343 * @mflags are mount flags as specified on command-line -- used only to save
2344 * MS_RDONLY which is allowed for non-root users.
2346 static int apply_fs(struct libmnt_context
*cxt
, struct libmnt_fs
*fs
, unsigned long mflags
)
2348 struct libmnt_optlist
*ls
;
2353 if (!cxt
->optsmode
) {
2354 if (mnt_context_is_restricted(cxt
)) {
2355 DBG(CXT
, ul_debugobj(cxt
, "force fstab usage for non-root users!"));
2356 cxt
->optsmode
= MNT_OMODE_USER
;
2358 DBG(CXT
, ul_debugobj(cxt
, "use default optsmode"));
2359 cxt
->optsmode
= MNT_OMODE_AUTO
;
2364 if (!mnt_context_get_fs(cxt
))
2367 DBG(CXT
, ul_debugobj(cxt
, "apply entry:"));
2368 DBG(CXT
, mnt_fs_print_debug(fs
, stderr
));
2369 DBG(CXT
, ul_debugobj(cxt
, "OPTSMODE (opt-part): ignore=%d, append=%d, prepend=%d, replace=%d",
2370 cxt
->optsmode
& MNT_OMODE_IGNORE
? 1 : 0,
2371 cxt
->optsmode
& MNT_OMODE_APPEND
? 1 : 0,
2372 cxt
->optsmode
& MNT_OMODE_PREPEND
? 1 : 0,
2373 cxt
->optsmode
& MNT_OMODE_REPLACE
? 1 : 0));
2375 /* copy from fs to our FS description
2377 rc
= mnt_fs_set_source(cxt
->fs
, mnt_fs_get_source(fs
));
2379 rc
= mnt_fs_set_target(cxt
->fs
, mnt_fs_get_target(fs
));
2381 if (!rc
&& !mnt_fs_get_fstype(cxt
->fs
))
2382 rc
= mnt_fs_set_fstype(cxt
->fs
, mnt_fs_get_fstype(fs
));
2384 if (!rc
&& !mnt_fs_get_root(cxt
->fs
) && mnt_fs_get_root(fs
))
2385 rc
= mnt_fs_set_root(cxt
->fs
, mnt_fs_get_root(fs
));
2390 ls
= mnt_context_get_optlist(cxt
);
2396 if (cxt
->optsmode
& MNT_OMODE_IGNORE
)
2398 else if (cxt
->optsmode
& MNT_OMODE_REPLACE
) {
2399 rc
= mnt_optlist_set_optstr(ls
, mnt_fs_get_options(fs
), NULL
);
2401 /* mount --read-only for non-root users is allowed */
2402 if (rc
== 0 && (mflags
& MS_RDONLY
)
2403 && mnt_context_is_restricted(cxt
)
2404 && cxt
->optsmode
== MNT_OMODE_USER
)
2405 rc
= mnt_optlist_append_optstr(ls
, "ro", NULL
);
2407 else if (cxt
->optsmode
& MNT_OMODE_APPEND
)
2408 rc
= mnt_optlist_append_optstr(ls
, mnt_fs_get_options(fs
), NULL
);
2410 else if (cxt
->optsmode
& MNT_OMODE_PREPEND
)
2411 rc
= mnt_optlist_prepend_optstr(ls
, mnt_fs_get_options(fs
), NULL
);
2414 cxt
->flags
|= MNT_FL_TAB_APPLIED
;
2417 DBG(CXT
, ul_debugobj(cxt
, "final entry [rc=%d]", rc
));
2418 DBG(CXT
, mnt_fs_print_debug(cxt
->fs
, stderr
));
2423 static int apply_table(struct libmnt_context
*cxt
, struct libmnt_table
*tb
,
2424 int direction
, unsigned long mflags
)
2426 struct libmnt_fs
*fs
= NULL
;
2427 const char *src
, *tgt
;
2432 src
= mnt_fs_get_source(cxt
->fs
);
2433 tgt
= mnt_fs_get_target(cxt
->fs
);
2436 fs
= mnt_table_find_pair(tb
, src
, tgt
, direction
);
2439 fs
= mnt_table_find_source(tb
, src
, direction
);
2441 fs
= mnt_table_find_target(tb
, tgt
, direction
);
2443 if (!fs
&& mnt_context_is_swapmatch(cxt
)) {
2444 /* swap source and target (if @src is not LABEL/UUID),
2449 * the path could be a mountpoint as well as a source (for
2450 * example bind mount, symlink to a device, ...).
2452 if (src
&& !mnt_fs_get_tag(cxt
->fs
, NULL
, NULL
))
2453 fs
= mnt_table_find_target(tb
, src
, direction
);
2455 fs
= mnt_table_find_source(tb
, tgt
, direction
);
2460 return -MNT_ERR_NOFSTAB
; /* not found */
2462 return apply_fs(cxt
, fs
, mflags
);
2465 /* apply @fs to @cxt -- use mnt_context_apply_fstab() if not sure
2467 int mnt_context_apply_fs(struct libmnt_context
*cxt
, struct libmnt_fs
*fs
)
2469 return apply_fs(cxt
, fs
, 0);
2473 * mnt_context_apply_fstab:
2474 * @cxt: mount context
2476 * This function is optional.
2478 * Returns: 0 on success, negative number in case of error.
2480 int mnt_context_apply_fstab(struct libmnt_context
*cxt
)
2482 int rc
= -1, isremount
= 0, iscmdbind
= 0;
2483 struct libmnt_ns
*ns_old
;
2484 struct libmnt_table
*tab
= NULL
;
2485 const char *src
= NULL
, *tgt
= NULL
;
2486 unsigned long mflags
= 0;
2488 if (!cxt
|| !cxt
->fs
)
2491 if (mnt_context_tab_applied(cxt
)) { /* already applied */
2492 DBG(CXT
, ul_debugobj(cxt
, "fstab already applied -- skip"));
2496 if (mnt_context_is_restricted(cxt
)) {
2497 DBG(CXT
, ul_debugobj(cxt
, "force fstab usage for non-root users!"));
2498 cxt
->optsmode
= MNT_OMODE_USER
;
2499 } else if (cxt
->optsmode
== 0) {
2500 DBG(CXT
, ul_debugobj(cxt
, "use default optsmode"));
2501 cxt
->optsmode
= MNT_OMODE_AUTO
;
2502 } else if (cxt
->optsmode
& MNT_OMODE_NOTAB
) {
2503 cxt
->optsmode
&= ~MNT_OMODE_FSTAB
;
2504 cxt
->optsmode
&= ~MNT_OMODE_MTAB
;
2505 cxt
->optsmode
&= ~MNT_OMODE_FORCE
;
2508 if (mnt_context_get_mflags(cxt
, &mflags
) == 0) {
2509 isremount
= !!(mflags
& MS_REMOUNT
);
2510 iscmdbind
= !!(mflags
& MS_BIND
);
2514 src
= mnt_fs_get_source(cxt
->fs
);
2515 tgt
= mnt_fs_get_target(cxt
->fs
);
2518 DBG(CXT
, ul_debugobj(cxt
, "OPTSMODE (file-part): force=%d, fstab=%d, mtab=%d",
2519 cxt
->optsmode
& MNT_OMODE_FORCE
? 1 : 0,
2520 cxt
->optsmode
& MNT_OMODE_FSTAB
? 1 : 0,
2521 cxt
->optsmode
& MNT_OMODE_MTAB
? 1 : 0));
2523 /* fstab is not required if source and target are specified */
2524 if (src
&& tgt
&& !(cxt
->optsmode
& MNT_OMODE_FORCE
)) {
2525 DBG(CXT
, ul_debugobj(cxt
, "fstab not required -- skip"));
2530 && !(cxt
->optsmode
& MNT_OMODE_FSTAB
)
2531 && !(cxt
->optsmode
& MNT_OMODE_MTAB
)) {
2532 DBG(CXT
, ul_debugobj(cxt
, "only target; fstab/mtab not required "
2533 "-- skip, probably MS_PROPAGATION"));
2537 /* let's initialize cxt->fs */
2538 ignore_result( mnt_context_get_fs(cxt
) );
2540 ns_old
= mnt_context_switch_target_ns(cxt
);
2542 return -MNT_ERR_NAMESPACE
;
2545 if (cxt
->optsmode
& MNT_OMODE_FSTAB
) {
2546 DBG(CXT
, ul_debugobj(cxt
, "trying to apply fstab (src=%s, target=%s)", src
, tgt
));
2547 rc
= mnt_context_get_fstab(cxt
, &tab
);
2549 rc
= apply_table(cxt
, tab
, MNT_ITER_FORWARD
, mflags
);
2553 if (rc
< 0 && (cxt
->optsmode
& MNT_OMODE_MTAB
)
2554 && (isremount
|| cxt
->action
== MNT_ACT_UMOUNT
)) {
2555 DBG(CXT
, ul_debugobj(cxt
, "trying to apply mountinfo (src=%s, target=%s)", src
, tgt
));
2557 rc
= mnt_context_get_mountinfo_for_target(cxt
, &tab
, tgt
);
2559 rc
= mnt_context_get_mountinfo(cxt
, &tab
);
2561 rc
= apply_table(cxt
, tab
, MNT_ITER_BACKWARD
, mflags
);
2564 if (!mnt_context_switch_ns(cxt
, ns_old
))
2565 return -MNT_ERR_NAMESPACE
;
2568 if (!mnt_context_is_restricted(cxt
)
2571 DBG(CXT
, ul_debugobj(cxt
, "only target; ignore missing mountinfo entry on remount"));
2575 DBG(CXT
, ul_debugobj(cxt
, "failed to find entry in fstab/mountinfo [rc=%d]: %m", rc
));
2577 /* force to "not found in fstab/mountinfo" error, the details why
2578 * not found are not so important and may be misinterpreted by
2579 * applications... */
2580 rc
= -MNT_ERR_NOFSTAB
;
2583 } else if (isremount
&& !iscmdbind
&& cxt
->optlist
) {
2585 /* ignore "bind" on remount when the flag is read from fstab */
2586 mnt_optlist_remove_named(cxt
->optlist
, "bind", NULL
);
2592 * mnt_context_tab_applied:
2593 * @cxt: mount context
2595 * Returns: 1 if fstab (or mountinfo) has been applied to the context, or 0.
2597 int mnt_context_tab_applied(struct libmnt_context
*cxt
)
2599 return cxt
->flags
& MNT_FL_TAB_APPLIED
;
2603 * This is not a public function!
2605 * Returns 1 if *only propagation flags* change is requested.
2607 int mnt_context_propagation_only(struct libmnt_context
*cxt
)
2609 struct libmnt_optlist
*ls
;
2611 if (cxt
->action
!= MNT_ACT_MOUNT
)
2613 if (cxt
->mountdata
|| cxt
->fs
== NULL
)
2615 if (cxt
->fs
->fstype
&& strcmp(cxt
->fs
->fstype
, "none") != 0)
2617 if (cxt
->fs
->source
&& strcmp(cxt
->fs
->source
, "none") != 0)
2620 ls
= mnt_context_get_optlist(cxt
);
2621 return ls
? mnt_optlist_is_propagation_only(ls
) : 0;
2625 * mnt_context_get_status:
2626 * @cxt: mount context
2628 * Global libmount status.
2630 * The real exit code of the mount.type helper has to be tested by
2631 * mnt_context_get_helper_status(). The mnt_context_get_status() only informs
2632 * that exec() has been successful.
2634 * Returns: 1 if mount.type or mount(2) syscall has been successfully called.
2636 int mnt_context_get_status(struct libmnt_context
*cxt
)
2638 return !cxt
->syscall_status
|| !cxt
->helper_exec_status
;
2642 * mnt_context_helper_executed:
2643 * @cxt: mount context
2645 * Returns: 1 if mount.type helper has been executed, or 0.
2647 int mnt_context_helper_executed(struct libmnt_context
*cxt
)
2649 return cxt
->helper_exec_status
!= 1;
2653 * mnt_context_get_helper_status:
2654 * @cxt: mount context
2656 * Return: mount.type helper exit status, result is reliable only if
2657 * mnt_context_helper_executed() returns 1.
2659 int mnt_context_get_helper_status(struct libmnt_context
*cxt
)
2661 return cxt
->helper_status
;
2665 * mnt_context_syscall_called:
2666 * @cxt: mount context
2668 * Returns: 1 if mount(2) syscall has been called, or 0.
2670 int mnt_context_syscall_called(struct libmnt_context
*cxt
)
2672 return cxt
->syscall_status
!= 1;
2676 * mnt_context_get_syscall_errno:
2677 * @cxt: mount context
2679 * The result from this function is reliable only if
2680 * mnt_context_syscall_called() returns 1.
2682 * Returns: mount(2) errno if the syscall failed or 0.
2684 int mnt_context_get_syscall_errno(struct libmnt_context
*cxt
)
2686 if (cxt
->syscall_status
< 0)
2687 return -cxt
->syscall_status
;
2692 * mnt_context_set_syscall_status:
2693 * @cxt: mount context
2694 * @status: mount(2) status
2696 * The @status should be 0 on success, or negative number on error (-errno).
2698 * This function is intended for cases where mount/umount is called externally,
2699 * rather than by libmount.
2701 * Returns: 0 or negative number in case of error.
2703 int mnt_context_set_syscall_status(struct libmnt_context
*cxt
, int status
)
2708 DBG(CXT
, ul_debugobj(cxt
, "syscall status set to: %d", status
));
2709 cxt
->syscall_status
= status
;
2713 /* Use this for syscalls called from libmount */
2714 void mnt_context_syscall_save_status( struct libmnt_context
*cxt
,
2715 const char *syscallname
,
2719 DBG(CXT
, ul_debug("syscall '%s' [failed: %m]", syscallname
));
2720 cxt
->syscall_status
= -errno
;
2721 cxt
->syscall_name
= syscallname
;
2723 DBG(CXT
, ul_debug("syscall '%s' [success]", syscallname
));
2724 cxt
->syscall_status
= 0;
2728 void mnt_context_syscall_reset_status(struct libmnt_context
*cxt
)
2730 DBG(CXT
, ul_debug("reset syscall status"));
2731 cxt
->syscall_status
= 0;
2732 cxt
->syscall_name
= NULL
;
2734 mnt_context_reset_mesgs(cxt
);
2737 void mnt_context_reset_mesgs(struct libmnt_context
*cxt
)
2739 DBG(CXT
, ul_debug("reset messages"));
2740 ul_strv_free(cxt
->mesgs
);
2744 int mnt_context_append_mesg(struct libmnt_context
*cxt
, const char *msg
)
2747 DBG(CXT
, ul_debug("mesg: '%s'", msg
));
2749 return ul_strv_extend(&cxt
->mesgs
, msg
);
2752 int mnt_context_sprintf_mesg(struct libmnt_context
*cxt
, const char *msg
, ...)
2758 rc
= ul_strv_extendv(&cxt
->mesgs
, msg
, ap
);
2764 int mnt_context_read_mesgs(struct libmnt_context
*cxt
, int fd
)
2766 uint8_t buf
[BUFSIZ
];
2774 while ((sz
= read(fd
, buf
, sizeof(buf
) - 1)) != -1) {
2778 if (buf
[sz
- 1] == '\n')
2786 mnt_context_append_mesg(cxt
, (char *) buf
);
2795 * mnt_context_get_nmesgs:
2796 * @cxt: mount context
2797 * @type: type of message (see fsopen() man page) or zero for all types
2799 * Returns: number of messages
2803 size_t mnt_context_get_nmesgs(struct libmnt_context
*cxt
, char type
)
2808 if (!cxt
|| !cxt
->mesgs
)
2811 n
= ul_strv_length(cxt
->mesgs
);
2814 UL_STRV_FOREACH(s
, cxt
->mesgs
) {
2815 if (*s
&& **s
== type
)
2824 * mnt_context_get_mesgs:
2825 * @cxt: mount context
2827 * Returns: NULL terminated array of messages or NULL
2831 char **mnt_context_get_mesgs(struct libmnt_context
*cxt
)
2833 return cxt
? cxt
->mesgs
: NULL
;
2837 * mnt_context_strerror
2840 * @bufsiz: size of the buffer
2842 * Not implemented, deprecated in favor or mnt_context_get_excode().
2844 * Returns: 0 or negative number in case of error.
2846 int mnt_context_strerror(struct libmnt_context
*cxt
__attribute__((__unused__
)),
2847 char *buf
__attribute__((__unused__
)),
2848 size_t bufsiz
__attribute__((__unused__
)))
2850 /* TODO: based on cxt->syscall_errno or cxt->helper_status */
2855 * mnt_context_enable_noautofs:
2857 * @ignore: ignore or don't ignore
2859 * Enable/disable ignore autofs mount table entries on reading the
2860 * mount table. Only effective if the "ignore" mount option is being
2861 * used for autofs mounts (such as if automount(8) has been configured
2864 int mnt_context_enable_noautofs(struct libmnt_context
*cxt
, int ignore
)
2868 cxt
->noautofs
= ignore
? 1 : 0;
2872 int mnt_context_get_generic_excode(int rc
, char *buf
, size_t bufsz
, const char *fmt
, ...)
2877 return MNT_EX_SUCCESS
;
2881 /* we need to support "%m" */
2882 errno
= rc
< 0 ? -rc
: rc
;
2884 if (buf
&& bufsz
&& vsnprintf(buf
, bufsz
, fmt
, va
) < 0)
2904 * mnt_context_get_excode:
2906 * @rc: return code of the previous operation
2907 * @buf: buffer to print error message (optional)
2908 * @bufsz: size of the buffer
2910 * This function analyzes context, [u]mount syscall and external helper status
2911 * and @mntrc and generates unified return code (see MNT_EX_*) as expected
2912 * from mount(8) or umount(8).
2914 * If the external helper (e.g. /sbin/mount.type) has been executed than it
2915 * returns status from wait() of the helper. It's not libmount fail if helper
2916 * returns some crazy undocumented codes... See mnt_context_helper_executed()
2917 * and mnt_context_get_helper_status(). Note that mount(8) and umount(8) utils
2918 * always return code from helper without extra care about it.
2920 * The current implementation does not read error message from external
2923 * If the argument @buf is not NULL then error message is generated (if
2926 * The @mntrc is usually return code from mnt_context_mount(),
2927 * mnt_context_umount(), or 'mntrc' as returned by mnt_context_next_mount().
2931 * Returns: MNT_EX_* codes.
2933 int mnt_context_get_excode(
2934 struct libmnt_context
*cxt
,
2940 *buf
= '\0'; /* for sure */
2942 if (!cxt
->enabled_textdomain
) {
2943 bindtextdomain(LIBMOUNT_TEXTDOMAIN
, LOCALEDIR
);
2944 cxt
->enabled_textdomain
= 1;
2948 switch (cxt
->action
) {
2950 rc
= mnt_context_get_mount_excode(cxt
, rc
, buf
, bufsz
);
2952 case MNT_ACT_UMOUNT
:
2953 rc
= mnt_context_get_umount_excode(cxt
, rc
, buf
, bufsz
);
2957 rc
= mnt_context_get_generic_excode(rc
, buf
, bufsz
,
2958 _("operation failed: %m"));
2960 rc
= MNT_EX_SUCCESS
;
2964 DBG(CXT
, ul_debugobj(cxt
, "excode: rc=%d message=\"%s\"", rc
,
2965 buf
? buf
: "<no-message>"));
2970 * mnt_context_init_helper
2971 * @cxt: mount context
2972 * @action: MNT_ACT_{UMOUNT,MOUNT}
2973 * @flags: not used now
2975 * This function informs libmount that used from [u]mount.type helper.
2977 * The function also calls mnt_context_disable_helpers() to avoid recursive
2978 * mount.type helpers calling. It you really want to call another
2979 * mount.type helper from your helper, then you have to explicitly enable this
2982 * mnt_context_disable_helpers(cxt, FALSE);
2984 * Returns: 0 on success, negative number in case of error.
2986 int mnt_context_init_helper(struct libmnt_context
*cxt
, int action
,
2987 int flags
__attribute__((__unused__
)))
2994 rc
= mnt_context_disable_helpers(cxt
, TRUE
);
2996 rc
= set_flag(cxt
, MNT_FL_HELPER
, 1);
2998 cxt
->action
= action
;
3000 DBG(CXT
, ul_debugobj(cxt
, "initialized for [u]mount.<type> helper [rc=%d]", rc
));
3005 * libmount used in /sbin/[u]mount.<type> helper
3007 int mnt_context_within_helper(struct libmnt_context
*cxt
)
3009 return cxt
&& (cxt
->flags
& MNT_FL_HELPER
);
3013 * mnt_context_helper_setopt:
3015 * @c: getopt() result
3016 * @arg: getopt() optarg
3018 * This function applies the [u]mount.type command line option (for example parsed
3019 * by getopt or getopt_long) to @cxt. All unknown options are ignored and
3020 * then 1 is returned.
3022 * Returns: negative number on error, 1 if @c is unknown option, 0 on success.
3024 int mnt_context_helper_setopt(struct libmnt_context
*cxt
, int c
, char *arg
)
3027 switch(cxt
->action
) {
3029 return mnt_context_mount_setopt(cxt
, c
, arg
);
3030 case MNT_ACT_UMOUNT
:
3031 return mnt_context_umount_setopt(cxt
, c
, arg
);
3038 * mnt_context_is_fs_mounted:
3041 * @mounted: returns 1 for mounted and 0 for non-mounted filesystems
3043 * Please, read the mnt_table_is_fs_mounted() description!
3045 * Returns: 0 on success and negative number in case of error.
3047 int mnt_context_is_fs_mounted(struct libmnt_context
*cxt
,
3048 struct libmnt_fs
*fs
, int *mounted
)
3050 struct libmnt_table
*mountinfo
, *orig
;
3052 struct libmnt_ns
*ns_old
;
3054 if (!cxt
|| !fs
|| !mounted
)
3057 ns_old
= mnt_context_switch_target_ns(cxt
);
3059 return -MNT_ERR_NAMESPACE
;
3061 orig
= cxt
->mountinfo
;
3062 rc
= mnt_context_get_mountinfo(cxt
, &mountinfo
);
3063 if (rc
== -ENOENT
&& mnt_fs_streq_target(fs
, "/proc")) {
3065 mnt_unref_table(cxt
->mountinfo
);
3066 cxt
->mountinfo
= NULL
;
3069 rc
= 0; /* /proc not mounted */
3071 } else if (rc
== 0) {
3072 *mounted
= __mnt_table_is_fs_mounted(mountinfo
, fs
,
3073 mnt_context_get_target_prefix(cxt
));
3077 if (!mnt_context_switch_ns(cxt
, ns_old
))
3078 return -MNT_ERR_NAMESPACE
;
3082 static int mnt_context_add_child(struct libmnt_context
*cxt
, pid_t pid
)
3089 pids
= reallocarray(cxt
->children
, cxt
->nchildren
+ 1, sizeof(pid_t
));
3093 DBG(CXT
, ul_debugobj(cxt
, "add new child %d", pid
));
3094 cxt
->children
= pids
;
3095 cxt
->children
[cxt
->nchildren
++] = pid
;
3100 int mnt_fork_context(struct libmnt_context
*cxt
)
3106 if (!mnt_context_is_parent(cxt
))
3109 DBG(CXT
, ul_debugobj(cxt
, "forking context"));
3116 case -1: /* error */
3117 DBG(CXT
, ul_debugobj(cxt
, "fork failed %m"));
3121 cxt
->pid
= getpid();
3122 mnt_context_enable_fork(cxt
, FALSE
);
3123 DBG(CXT
, ul_debugobj(cxt
, "child created"));
3127 rc
= mnt_context_add_child(cxt
, pid
);
3134 int mnt_context_wait_for_children(struct libmnt_context
*cxt
,
3135 int *nchildren
, int *nerrs
)
3142 assert(mnt_context_is_parent(cxt
));
3144 for (i
= 0; i
< cxt
->nchildren
; i
++) {
3145 pid_t pid
= cxt
->children
[i
];
3146 int rc
= 0, ret
= 0;
3151 DBG(CXT
, ul_debugobj(cxt
,
3152 "waiting for child (%d/%d): %d",
3153 i
+ 1, cxt
->nchildren
, pid
));
3155 rc
= waitpid(pid
, &ret
, 0);
3157 } while (rc
== -1 && errno
== EINTR
);
3162 if (rc
!= -1 && nerrs
) {
3164 (*nerrs
) += WEXITSTATUS(ret
) == 0 ? 0 : 1;
3168 cxt
->children
[i
] = 0;
3172 free(cxt
->children
);
3173 cxt
->children
= NULL
;
3177 static void close_ns(struct libmnt_ns
*ns
)
3185 mnt_unref_cache(ns
->cache
);
3190 * mnt_context_set_target_ns:
3191 * @cxt: mount context
3192 * @path: path to target namespace or NULL
3194 * Sets target namespace to namespace represented by @path. If @path is NULL,
3195 * target namespace is cleared.
3197 * This function sets errno to ENOSYS and returns error if libmount is
3198 * compiled without namespaces support.
3200 * Returns: 0 on success, negative number in case of error.
3204 int mnt_context_set_target_ns(struct libmnt_context
*cxt
, const char *path
)
3209 DBG(CXT
, ul_debugobj(cxt
, "Setting %s as target namespace", path
));
3213 close_ns(&cxt
->ns_orig
);
3214 close_ns(&cxt
->ns_tgt
);
3218 #ifdef USE_LIBMOUNT_SUPPORT_NAMESPACES
3224 /* open original namespace */
3225 if (cxt
->ns_orig
.fd
== -1) {
3226 cxt
->ns_orig
.fd
= open("/proc/self/ns/mnt", O_RDONLY
| O_CLOEXEC
);
3227 if (cxt
->ns_orig
.fd
== -1)
3229 cxt
->ns_orig
.cache
= NULL
;
3232 /* open target (wanted) namespace */
3233 tmp
= open(path
, O_RDONLY
| O_CLOEXEC
);
3237 /* test whether namespace switching works */
3238 DBG(CXT
, ul_debugobj(cxt
, "Trying whether namespace is valid"));
3239 if (setns(tmp
, CLONE_NEWNS
)
3240 || setns(cxt
->ns_orig
.fd
, CLONE_NEWNS
)) {
3242 DBG(CXT
, ul_debugobj(cxt
, "setns(2) failed [errno=%d %m]", errno
));
3246 close_ns(&cxt
->ns_tgt
);
3248 cxt
->ns_tgt
.fd
= tmp
;
3249 cxt
->ns_tgt
.cache
= NULL
;
3256 #else /* ! USE_LIBMOUNT_SUPPORT_NAMESPACES */
3263 * mnt_context_get_target_ns:
3264 * @cxt: mount context
3266 * Returns: pointer to target namespace
3270 struct libmnt_ns
*mnt_context_get_target_ns(struct libmnt_context
*cxt
)
3272 return &cxt
->ns_tgt
;
3276 * mnt_context_get_origin_ns:
3277 * @cxt: mount context
3279 * Returns: pointer to original namespace
3283 struct libmnt_ns
*mnt_context_get_origin_ns(struct libmnt_context
*cxt
)
3285 return &cxt
->ns_orig
;
3290 * mnt_context_switch_ns:
3291 * @cxt: mount context
3292 * @ns: namespace to switch to
3294 * Switch to namespace specified by ns
3299 * struct libmnt_ns *ns_old;
3300 * ns_old = mnt_context_switch_ns(cxt, mnt_context_get_target_ns(cxt));
3302 * mnt_context_switch_ns(cxt, ns_old);
3304 * </informalexample>
3306 * Returns: pointer to previous namespace or NULL on error
3310 struct libmnt_ns
*mnt_context_switch_ns(struct libmnt_context
*cxt
, struct libmnt_ns
*ns
)
3312 struct libmnt_ns
*old
= NULL
;
3318 * If mnt_context_set_target_ns() has never been used than @ns file
3319 * descriptor is -1 and this function is noop.
3322 if (ns
== old
|| ns
->fd
== -1)
3325 #ifdef USE_LIBMOUNT_SUPPORT_NAMESPACES
3326 /* remember the current cache */
3327 if (old
->cache
!= cxt
->cache
) {
3328 mnt_unref_cache(old
->cache
);
3329 old
->cache
= cxt
->cache
;
3330 mnt_ref_cache(old
->cache
);
3334 DBG(CXT
, ul_debugobj(cxt
, "Switching to %s namespace",
3335 ns
== mnt_context_get_target_ns(cxt
) ? "target" :
3336 ns
== mnt_context_get_origin_ns(cxt
) ? "original" : "other"));
3338 if (setns(ns
->fd
, CLONE_NEWNS
)) {
3341 DBG(CXT
, ul_debugobj(cxt
, "setns(2) failed [errno=%d %m]", errno
));
3346 /* update pointer to the current namespace */
3349 /* update pointer to the cache */
3350 mnt_unref_cache(cxt
->cache
);
3351 cxt
->cache
= ns
->cache
;
3352 mnt_ref_cache(cxt
->cache
);
3353 #endif /* USE_LIBMOUNT_SUPPORT_NAMESPACES */
3359 * mnt_context_switch_origin_ns:
3360 * @cxt: mount context
3362 * Switch to original namespace
3364 * This is shorthand for
3367 * mnt_context_switch_ns(cxt, mnt_context_get_origin_ns(cxt));
3369 * </informalexample>
3371 * Returns: pointer to previous namespace or NULL on error
3375 struct libmnt_ns
*mnt_context_switch_origin_ns(struct libmnt_context
*cxt
)
3377 return mnt_context_switch_ns(cxt
, mnt_context_get_origin_ns(cxt
));
3381 * mnt_context_switch_target_ns:
3382 * @cxt: mount context
3384 * Switch to target namespace
3386 * This is shorthand for
3389 * mnt_context_switch_ns(cxt, mnt_context_get_target_ns(cxt));
3391 * </informalexample>
3393 * Returns: pointer to previous namespace or NULL on error
3397 struct libmnt_ns
*mnt_context_switch_target_ns(struct libmnt_context
*cxt
)
3399 return mnt_context_switch_ns(cxt
, mnt_context_get_target_ns(cxt
));
3405 static int test_search_helper(struct libmnt_test
*ts
__attribute__((unused
)),
3406 int argc
, char *argv
[])
3408 struct libmnt_context
*cxt
;
3415 cxt
= mnt_new_context();
3421 mnt_context_get_fs(cxt
); /* just to fill cxt->fs */
3422 cxt
->flags
|= MNT_FL_MOUNTFLAGS_MERGED
; /* fake */
3424 rc
= mnt_context_prepare_helper(cxt
, "mount", type
);
3425 printf("helper is: %s\n", cxt
->helper
? cxt
->helper
: "not found");
3427 mnt_free_context(cxt
);
3432 static struct libmnt_lock
*lock
;
3434 static void lock_fallback(void)
3437 mnt_unlock_file(lock
);
3440 static int test_mount(struct libmnt_test
*ts
__attribute__((unused
)),
3441 int argc
, char *argv
[])
3443 int idx
= 1, rc
= 0;
3444 struct libmnt_context
*cxt
;
3449 cxt
= mnt_new_context();
3453 if (!strcmp(argv
[idx
], "-o")) {
3454 mnt_context_set_options(cxt
, argv
[idx
+ 1]);
3457 if (!strcmp(argv
[idx
], "-t")) {
3458 /* TODO: use mnt_context_set_fstype_pattern() */
3459 mnt_context_set_fstype(cxt
, argv
[idx
+ 1]);
3463 if (argc
== idx
+ 1)
3464 /* mount <mountpoint>|<device> */
3465 mnt_context_set_target(cxt
, argv
[idx
++]);
3467 else if (argc
== idx
+ 2) {
3468 /* mount <device> <mountpoint> */
3469 mnt_context_set_source(cxt
, argv
[idx
++]);
3470 mnt_context_set_target(cxt
, argv
[idx
++]);
3473 /* this is unnecessary! -- libmount is able to internally
3474 * create and manage the lock
3476 lock
= mnt_context_get_lock(cxt
);
3478 atexit(lock_fallback
);
3480 rc
= mnt_context_mount(cxt
);
3482 warn("failed to mount");
3484 printf("successfully mounted\n");
3486 lock
= NULL
; /* because we use atexit lock_fallback */
3487 mnt_free_context(cxt
);
3491 static int test_umount(struct libmnt_test
*ts
__attribute__((unused
)),
3492 int argc
, char *argv
[])
3494 int idx
= 1, rc
= 0;
3495 struct libmnt_context
*cxt
;
3500 cxt
= mnt_new_context();
3504 if (!strcmp(argv
[idx
], "-t")) {
3505 mnt_context_set_fstype(cxt
, argv
[idx
+ 1]);
3509 if (!strcmp(argv
[idx
], "-f")) {
3510 mnt_context_enable_force(cxt
, TRUE
);
3514 if (!strcmp(argv
[idx
], "-l")) {
3515 mnt_context_enable_lazy(cxt
, TRUE
);
3519 if (!strcmp(argv
[idx
], "-r")) {
3520 mnt_context_enable_rdonly_umount(cxt
, TRUE
);
3524 if (argc
== idx
+ 1) {
3525 /* mount <mountpoint>|<device> */
3526 mnt_context_set_target(cxt
, argv
[idx
++]);
3532 lock
= mnt_context_get_lock(cxt
);
3534 atexit(lock_fallback
);
3536 rc
= mnt_context_umount(cxt
);
3538 printf("failed to umount\n");
3540 printf("successfully umounted\n");
3542 lock
= NULL
; /* because we use atexit lock_fallback */
3543 mnt_free_context(cxt
);
3547 static int test_flags(struct libmnt_test
*ts
__attribute__((unused
)),
3548 int argc
, char *argv
[])
3550 int idx
= 1, rc
= 0;
3551 struct libmnt_context
*cxt
;
3552 const char *opt
= NULL
;
3553 unsigned long flags
= 0;
3558 cxt
= mnt_new_context();
3562 if (!strcmp(argv
[idx
], "-o")) {
3563 mnt_context_set_options(cxt
, argv
[idx
+ 1]);
3567 if (argc
== idx
+ 1)
3568 /* mount <mountpoint>|<device> */
3569 mnt_context_set_target(cxt
, argv
[idx
++]);
3571 rc
= mnt_context_prepare_mount(cxt
);
3573 printf("failed to prepare mount %s\n", strerror(-rc
));
3575 opt
= mnt_fs_get_options(cxt
->fs
);
3577 fprintf(stdout
, "options: %s\n", opt
);
3579 mnt_context_get_mflags(cxt
, &flags
);
3580 fprintf(stdout
, "flags: %08lx\n", flags
);
3582 mnt_free_context(cxt
);
3586 static int test_cxtsync(struct libmnt_test
*ts
__attribute__((unused
)),
3587 int argc
, char *argv
[])
3589 struct libmnt_context
*cxt
;
3590 struct libmnt_fs
*fs
;
3591 unsigned long flags
= 0;
3601 rc
= mnt_fs_set_options(fs
, argv
[1]);
3605 cxt
= mnt_new_context();
3609 rc
= mnt_context_set_fs(cxt
, fs
);
3613 rc
= mnt_context_append_options(cxt
, argv
[2]);
3617 rc
= mnt_fs_append_options(fs
, argv
[3]);
3621 mnt_context_get_mflags(cxt
, &flags
);
3623 printf(" fs options: %s\n", mnt_fs_get_options(fs
));
3624 printf("context options: %s\n", mnt_context_get_options(cxt
));
3625 printf(" context mflags: %08lx\n", flags
);
3627 mnt_free_context(cxt
);
3631 static int test_mountall(struct libmnt_test
*ts
__attribute__((unused
)),
3632 int argc
, char *argv
[])
3634 struct libmnt_context
*cxt
;
3635 struct libmnt_iter
*itr
;
3636 struct libmnt_fs
*fs
;
3637 int mntrc
, ignored
, idx
= 1;
3639 cxt
= mnt_new_context();
3640 itr
= mnt_new_iter(MNT_ITER_FORWARD
);
3646 if (argv
[idx
] && !strcmp(argv
[idx
], "-O")) {
3647 mnt_context_set_options_pattern(cxt
, argv
[idx
+ 1]);
3650 if (argv
[idx
] && !strcmp(argv
[idx
], "-t"))
3651 mnt_context_set_fstype_pattern(cxt
, argv
[idx
+ 1]);
3654 while (mnt_context_next_mount(cxt
, itr
, &fs
, &mntrc
, &ignored
) == 0) {
3656 const char *tgt
= mnt_fs_get_target(fs
);
3659 printf("%s: ignored: not match\n", tgt
);
3660 else if (ignored
== 2)
3661 printf("%s: ignored: already mounted\n", tgt
);
3663 else if (!mnt_context_get_status(cxt
)) {
3666 warn("%s: mount failed", tgt
);
3668 warnx("%s: mount failed", tgt
);
3670 printf("%s: successfully mounted\n", tgt
);
3673 mnt_free_context(cxt
);
3679 int main(int argc
, char *argv
[])
3681 struct libmnt_test tss
[] = {
3682 { "--mount", test_mount
, "[-o <opts>] [-t <type>] <spec>|<src> <target>" },
3683 { "--umount", test_umount
, "[-t <type>] [-f][-l][-r] <src>|<target>" },
3684 { "--mount-all", test_mountall
, "[-O <pattern>] [-t <pattern] mount all filesystems from fstab" },
3685 { "--flags", test_flags
, "[-o <opts>] <spec>" },
3686 { "--cxtsync", test_cxtsync
, "<fsopts> <cxtopts> <fsopts>" },
3687 { "--search-helper", test_search_helper
, "<fstype>" },
3690 umask(S_IWGRP
|S_IWOTH
); /* to be compatible with mount(8) */
3692 return mnt_run_test(tss
, argc
, argv
);
3695 #endif /* TEST_PROGRAM */