]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - libmount/src/context.c
6db71f4e4777f4b072765893aa40c75cae05a9b7
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"
49 * Returns: newly allocated mount context
51 struct libmnt_context
*mnt_new_context(void)
53 struct libmnt_context
*cxt
;
56 cxt
= calloc(1, sizeof(*cxt
));
63 mnt_context_reset_status(cxt
);
67 cxt
->ns_cur
= &cxt
->ns_orig
;
69 cxt
->map_linux
= mnt_get_builtin_optmap(MNT_LINUX_MAP
);
70 cxt
->map_userspace
= mnt_get_builtin_optmap(MNT_USERSPACE_MAP
);
72 INIT_LIST_HEAD(&cxt
->hooksets_hooks
);
73 INIT_LIST_HEAD(&cxt
->hooksets_datas
);
75 /* if we're really root and aren't running setuid */
76 cxt
->restricted
= (uid_t
) 0 == ruid
&& ruid
== euid
? 0 : 1;
80 DBG(CXT
, ul_debugobj(cxt
, "----> allocate %s",
81 cxt
->restricted
? "[RESTRICTED]" : ""));
90 * Deallocates context struct.
92 void mnt_free_context(struct libmnt_context
*cxt
)
97 mnt_reset_context(cxt
);
99 free(cxt
->fstype_pattern
);
100 free(cxt
->optstr_pattern
);
101 free(cxt
->tgt_prefix
);
103 mnt_unref_table(cxt
->fstab
);
104 mnt_unref_cache(cxt
->cache
);
105 mnt_unref_fs(cxt
->fs
);
107 mnt_unref_optlist(cxt
->optlist_saved
);
108 mnt_unref_optlist(cxt
->optlist
);
110 mnt_free_lock(cxt
->lock
);
111 mnt_free_update(cxt
->update
);
113 mnt_context_set_target_ns(cxt
, NULL
);
117 DBG(CXT
, ul_debugobj(cxt
, "free"));
123 * @cxt: mount context
125 * Resets all information in the context that is directly related to
126 * the latest mount (spec, source, target, mount options, ...).
128 * The match patterns, target namespace, prefix, cached fstab, cached canonicalized
129 * paths and tags and [e]uid are not reset. You have to use
131 * mnt_context_set_fstab(cxt, NULL);
132 * mnt_context_set_cache(cxt, NULL);
133 * mnt_context_set_fstype_pattern(cxt, NULL);
134 * mnt_context_set_options_pattern(cxt, NULL);
135 * mnt_context_set_target_ns(cxt, NULL);
137 * to reset this stuff.
139 * Returns: 0 on success, negative number in case of error.
141 int mnt_reset_context(struct libmnt_context
*cxt
)
148 DBG(CXT
, ul_debugobj(cxt
, "<---- reset [status=%d] ---->",
149 mnt_context_get_status(cxt
)));
153 mnt_unref_fs(cxt
->fs
);
154 mnt_unref_table(cxt
->mountinfo
);
155 mnt_unref_table(cxt
->utab
);
156 mnt_unref_optlist(cxt
->optlist
);
161 cxt
->mountinfo
= NULL
;
165 cxt
->mountdata
= NULL
;
166 cxt
->flags
= MNT_FL_DEFAULT
;
168 cxt
->has_selinux_opt
= 0;
170 cxt
->map_linux
= mnt_get_builtin_optmap(MNT_LINUX_MAP
);
171 cxt
->map_userspace
= mnt_get_builtin_optmap(MNT_USERSPACE_MAP
);
173 mnt_context_reset_status(cxt
);
174 mnt_context_deinit_hooksets(cxt
);
176 if (cxt
->table_fltrcb
)
177 mnt_context_set_tabfilter(cxt
, NULL
, NULL
);
179 /* restore non-resettable flags */
180 cxt
->flags
|= (fl
& MNT_FL_NOMTAB
);
181 cxt
->flags
|= (fl
& MNT_FL_FAKE
);
182 cxt
->flags
|= (fl
& MNT_FL_SLOPPY
);
183 cxt
->flags
|= (fl
& MNT_FL_VERBOSE
);
184 cxt
->flags
|= (fl
& MNT_FL_NOHELPERS
);
185 cxt
->flags
|= (fl
& MNT_FL_LOOPDEL
);
186 cxt
->flags
|= (fl
& MNT_FL_LAZY
);
187 cxt
->flags
|= (fl
& MNT_FL_FORK
);
188 cxt
->flags
|= (fl
& MNT_FL_FORCE
);
189 cxt
->flags
|= (fl
& MNT_FL_NOCANONICALIZE
);
190 cxt
->flags
|= (fl
& MNT_FL_RDONLY_UMOUNT
);
191 cxt
->flags
|= (fl
& MNT_FL_RWONLY_MOUNT
);
192 cxt
->flags
|= (fl
& MNT_FL_NOSWAPMATCH
);
193 cxt
->flags
|= (fl
& MNT_FL_TABPATHS_CHECKED
);
195 mnt_context_apply_template(cxt
);
201 * Saves the current context setting (mount options, etc) to make it usable after
202 * mnt_reset_context() or by mnt_context_apply_template(). This is usable for
203 * example for mnt_context_next_mount() where for the next mount operation we
204 * need to restore to the original context setting.
206 * Returns: 0 on success, negative number in case of error.
208 int mnt_context_save_template(struct libmnt_context
*cxt
)
213 DBG(CXT
, ul_debugobj(cxt
, "saving template"));
215 /* reset old saved data */
216 mnt_unref_optlist(cxt
->optlist_saved
);
217 cxt
->optlist_saved
= NULL
;
220 cxt
->optlist_saved
= mnt_copy_optlist(cxt
->optlist
);
226 * Restores context FS setting from previously saved template (see
227 * mnt_context_save_template()).
229 * Returns: 0 on success, negative number in case of error.
231 int mnt_context_apply_template(struct libmnt_context
*cxt
)
237 mnt_unref_optlist(cxt
->optlist
);
241 if (cxt
->optlist_saved
) {
242 DBG(CXT
, ul_debugobj(cxt
, "restoring template"));
243 cxt
->optlist
= mnt_copy_optlist(cxt
->optlist_saved
);
249 int mnt_context_has_template(struct libmnt_context
*cxt
)
251 return cxt
&& cxt
->optlist_saved
? 1 : 0;
254 struct libmnt_context
*mnt_copy_context(struct libmnt_context
*o
)
256 struct libmnt_context
*n
;
258 n
= mnt_new_context();
262 DBG(CXT
, ul_debugobj(n
, "<---- clone ---->"));
267 n
->fs
= mnt_copy_fs(NULL
, o
->fs
);
272 n
->mountinfo
= o
->mountinfo
;
273 mnt_ref_table(n
->mountinfo
);
276 mnt_ref_table(n
->utab
);
278 if (strdup_between_structs(n
, o
, tgt_prefix
))
280 if (strdup_between_structs(n
, o
, helper
))
283 n
->map_linux
= o
->map_linux
;
284 n
->map_userspace
= o
->map_userspace
;
286 mnt_context_reset_status(n
);
288 n
->table_fltrcb
= o
->table_fltrcb
;
289 n
->table_fltrcb_data
= o
->table_fltrcb_data
;
291 n
->noautofs
= o
->noautofs
;
292 n
->has_selinux_opt
= o
->has_selinux_opt
;
301 * mnt_context_reset_status:
304 * Resets mount(2) and mount.type statuses, so mnt_context_do_mount() or
305 * mnt_context_do_umount() could be again called with the same settings.
307 * BE CAREFUL -- after this soft reset the libmount will NOT parse mount
308 * options, evaluate permissions or apply stuff from fstab.
310 * Returns: 0 on success, negative number in case of error.
312 int mnt_context_reset_status(struct libmnt_context
*cxt
)
317 cxt
->syscall_status
= 1; /* means not called yet */
318 cxt
->helper_exec_status
= 1;
319 cxt
->helper_status
= 0;
323 static int context_init_paths(struct libmnt_context
*cxt
, int writable
)
325 struct libmnt_ns
*ns_old
;
329 if (!cxt
->utab_path
) {
330 cxt
->utab_path
= mnt_get_utab_path();
331 DBG(CXT
, ul_debugobj(cxt
, "utab path initialized to: %s", cxt
->utab_path
));
335 return 0; /* only paths wanted */
336 if (mnt_context_is_nomtab(cxt
))
337 return 0; /* write mode overridden by mount -n */
338 if (cxt
->flags
& MNT_FL_TABPATHS_CHECKED
)
341 DBG(CXT
, ul_debugobj(cxt
, "checking for writable tab files"));
343 ns_old
= mnt_context_switch_target_ns(cxt
);
345 return -MNT_ERR_NAMESPACE
;
347 mnt_has_regular_utab(&cxt
->utab_path
, &cxt
->utab_writable
);
349 if (!mnt_context_switch_ns(cxt
, ns_old
))
350 return -MNT_ERR_NAMESPACE
;
352 cxt
->flags
|= MNT_FL_TABPATHS_CHECKED
;
356 int mnt_context_utab_writable(struct libmnt_context
*cxt
)
360 context_init_paths(cxt
, 1);
361 return cxt
->utab_writable
== 1;
364 const char *mnt_context_get_writable_tabpath(struct libmnt_context
*cxt
)
368 context_init_paths(cxt
, 1);
369 return cxt
->utab_path
;
373 static int set_flag(struct libmnt_context
*cxt
, int flag
, int enable
)
378 DBG(CXT
, ul_debugobj(cxt
, "enabling flag %04x", flag
));
381 DBG(CXT
, ul_debugobj(cxt
, "disabling flag %04x", flag
));
388 * mnt_context_is_restricted:
389 * @cxt: mount context
391 * Returns: 0 for an unrestricted mount (user is root), or 1 for non-root mounts
393 int mnt_context_is_restricted(struct libmnt_context
*cxt
)
395 return cxt
->restricted
;
399 * mnt_context_force_unrestricted:
400 * @cxt: mount context
402 * This function is DANGEROURS as it disables all security policies in libmount.
403 * Don't use if not sure. It removes "restricted" flag from the context, so
404 * libmount will use the current context as for root user.
406 * This function is designed for case you have no any suid permissions, so you
407 * can depend on kernel.
409 * Returns: 0 on success, negative number in case of error.
413 int mnt_context_force_unrestricted(struct libmnt_context
*cxt
)
415 if (mnt_context_is_restricted(cxt
)) {
416 DBG(CXT
, ul_debugobj(cxt
, "force UNRESTRICTED"));
424 * mnt_context_set_optsmode
425 * @cxt: mount context
426 * @mode: MNT_OMODE_* flags
428 * Controls how to use mount optionssource and target paths from fstab/mountinfo.
430 * @MNT_OMODE_IGNORE: ignore fstab options
432 * @MNT_OMODE_APPEND: append fstab options to existing options
434 * @MNT_OMODE_PREPEND: prepend fstab options to existing options
436 * @MNT_OMODE_REPLACE: replace existing options with options from fstab
438 * @MNT_OMODE_FORCE: always read fstab (although source and target are defined)
440 * @MNT_OMODE_FSTAB: read from fstab
442 * @MNT_OMODE_MTAB: read from mountinfo if fstab not enabled or failed
444 * @MNT_OMODE_NOTAB: do not read fstab/mountinfoat all
446 * @MNT_OMODE_AUTO: default mode (MNT_OMODE_PREPEND | MNT_OMODE_FSTAB | MNT_OMODE_MTAB)
448 * @MNT_OMODE_USER: default for non-root users (MNT_OMODE_REPLACE | MNT_OMODE_FORCE | MNT_OMODE_FSTAB)
452 * - MNT_OMODE_USER is always used if mount context is in restricted mode
453 * - MNT_OMODE_AUTO is used if nothing else is defined
454 * - the flags are evaluated in this order: MNT_OMODE_NOTAB, MNT_OMODE_FORCE,
455 * MNT_OMODE_FSTAB, MNT_OMODE_MTAB and then the mount options from fstab/mountinfo
456 * are set according to MNT_OMODE_{IGNORE,APPEND,PREPEND,REPLACE}
458 * Returns: 0 on success, negative number in case of error.
460 int mnt_context_set_optsmode(struct libmnt_context
*cxt
, int mode
)
464 cxt
->optsmode
= mode
;
469 * mnt_context_get_optsmode
470 * @cxt: mount context
472 * Returns: MNT_OMODE_* mask or zero.
475 int mnt_context_get_optsmode(struct libmnt_context
*cxt
)
477 return cxt
->optsmode
;
481 * mnt_context_disable_canonicalize:
482 * @cxt: mount context
483 * @disable: TRUE or FALSE
485 * Enable/disable paths canonicalization and tags evaluation. The libmount context
486 * canonicalizes paths when searching in fstab and when preparing source and target paths
487 * for mount(2) syscall.
489 * This function has an effect on the private (within context) fstab instance only
490 * (see mnt_context_set_fstab()). If you want to use an external fstab then you
491 * need to manage your private struct libmnt_cache (see mnt_table_set_cache(fstab,
494 * Returns: 0 on success, negative number in case of error.
496 int mnt_context_disable_canonicalize(struct libmnt_context
*cxt
, int disable
)
498 return set_flag(cxt
, MNT_FL_NOCANONICALIZE
, disable
);
502 * mnt_context_is_nocanonicalize:
503 * @cxt: mount context
505 * Returns: 1 if no-canonicalize mode is enabled or 0.
507 int mnt_context_is_nocanonicalize(struct libmnt_context
*cxt
)
509 return cxt
->flags
& MNT_FL_NOCANONICALIZE
? 1 : 0;
513 * mnt_context_enable_lazy:
514 * @cxt: mount context
515 * @enable: TRUE or FALSE
517 * Enable/disable lazy umount (see umount(8) man page, option -l).
519 * Returns: 0 on success, negative number in case of error.
521 int mnt_context_enable_lazy(struct libmnt_context
*cxt
, int enable
)
523 return set_flag(cxt
, MNT_FL_LAZY
, enable
);
527 * mnt_context_is_lazy:
528 * @cxt: mount context
530 * Returns: 1 if lazy umount is enabled or 0
532 int mnt_context_is_lazy(struct libmnt_context
*cxt
)
534 return cxt
->flags
& MNT_FL_LAZY
? 1 : 0;
538 * mnt_context_enable_onlyonce:
539 * @cxt: mount context
540 * @enable: TRUE or FALSE
542 * Enable/disable only-once mount (check if FS is not already mounted).
544 * Returns: 0 on success, negative number in case of error.
546 int mnt_context_enable_onlyonce(struct libmnt_context
*cxt
, int enable
)
548 return set_flag(cxt
, MNT_FL_ONLYONCE
, enable
);
552 * mnt_context_is_lazy:
553 * @cxt: mount context
555 * Returns: 1 if lazy umount is enabled or 0
557 int mnt_context_is_onlyonce(struct libmnt_context
*cxt
)
559 return cxt
->flags
& MNT_FL_ONLYONCE
? 1 : 0;
563 * mnt_context_enable_fork:
564 * @cxt: mount context
565 * @enable: TRUE or FALSE
567 * Enable/disable fork(2) call in mnt_context_next_mount() (see mount(8) man
570 * Returns: 0 on success, negative number in case of error.
572 int mnt_context_enable_fork(struct libmnt_context
*cxt
, int enable
)
574 return set_flag(cxt
, MNT_FL_FORK
, enable
);
578 * mnt_context_is_fork:
579 * @cxt: mount context
581 * Returns: 1 if fork (mount -F) is enabled or 0
583 int mnt_context_is_fork(struct libmnt_context
*cxt
)
585 return cxt
->flags
& MNT_FL_FORK
? 1 : 0;
589 * mnt_context_is_parent:
590 * @cxt: mount context
592 * Return: 1 if mount -F enabled and the current context is parent, or 0
594 int mnt_context_is_parent(struct libmnt_context
*cxt
)
596 return mnt_context_is_fork(cxt
) && cxt
->pid
== 0;
600 * mnt_context_is_child:
601 * @cxt: mount context
603 * Return: 1 f the current context is child, or 0
605 int mnt_context_is_child(struct libmnt_context
*cxt
)
607 /* See mnt_fork_context(), the for fork flag is always disabled
608 * for children to avoid recursive forking.
610 return !mnt_context_is_fork(cxt
) && cxt
->pid
;
614 * mnt_context_enable_rdonly_umount:
615 * @cxt: mount context
616 * @enable: TRUE or FALSE
618 * Enable/disable read-only remount on failed umount(2)
619 * (see umount(8) man page, option -r).
621 * Returns: 0 on success, negative number in case of error.
623 int mnt_context_enable_rdonly_umount(struct libmnt_context
*cxt
, int enable
)
625 return set_flag(cxt
, MNT_FL_RDONLY_UMOUNT
, enable
);
629 * mnt_context_is_rdonly_umount
630 * @cxt: mount context
632 * See also mnt_context_enable_rdonly_umount() and umount(8) man page,
635 * Returns: 1 if read-only remount failed umount(2) is enables or 0
637 int mnt_context_is_rdonly_umount(struct libmnt_context
*cxt
)
639 return cxt
->flags
& MNT_FL_RDONLY_UMOUNT
? 1 : 0;
643 * mnt_context_enable_rwonly_mount:
644 * @cxt: mount context
645 * @enable: TRUE or FALSE
647 * Force read-write mount; if enabled libmount will never try MS_RDONLY
648 * after failed mount(2) EROFS. (See mount(8) man page, option -w).
652 * Returns: 0 on success, negative number in case of error.
654 int mnt_context_enable_rwonly_mount(struct libmnt_context
*cxt
, int enable
)
656 return set_flag(cxt
, MNT_FL_RWONLY_MOUNT
, enable
);
660 * mnt_context_is_rwonly_mount
661 * @cxt: mount context
663 * See also mnt_context_enable_rwonly_mount() and mount(8) man page,
668 * Returns: 1 if only read-write mount is allowed.
670 int mnt_context_is_rwonly_mount(struct libmnt_context
*cxt
)
672 return cxt
->flags
& MNT_FL_RWONLY_MOUNT
? 1 : 0;
676 * mnt_context_forced_rdonly:
677 * @cxt: mount context
679 * See also mnt_context_enable_rwonly_mount().
683 * Returns: 1 if mounted read-only on write-protected device.
685 int mnt_context_forced_rdonly(struct libmnt_context
*cxt
)
687 return cxt
->flags
& MNT_FL_FORCED_RDONLY
? 1 : 0;
691 * mnt_context_disable_helpers:
692 * @cxt: mount context
693 * @disable: TRUE or FALSE
695 * Enable/disable /sbin/[u]mount.* helpers (see mount(8) man page, option -i).
697 * Returns: 0 on success, negative number in case of error.
699 int mnt_context_disable_helpers(struct libmnt_context
*cxt
, int disable
)
701 return set_flag(cxt
, MNT_FL_NOHELPERS
, disable
);
705 * mnt_context_is_nohelpers
706 * @cxt: mount context
708 * Returns: 1 if helpers are disabled (mount -i) or 0
710 int mnt_context_is_nohelpers(struct libmnt_context
*cxt
)
712 return cxt
->flags
& MNT_FL_NOHELPERS
? 1 : 0;
717 * mnt_context_enable_sloppy:
718 * @cxt: mount context
719 * @enable: TRUE or FALSE
721 * Set/unset sloppy mounting (see mount(8) man page, option -s).
723 * Returns: 0 on success, negative number in case of error.
725 int mnt_context_enable_sloppy(struct libmnt_context
*cxt
, int enable
)
727 return set_flag(cxt
, MNT_FL_SLOPPY
, enable
);
731 * mnt_context_is_sloppy:
732 * @cxt: mount context
734 * Returns: 1 if sloppy flag is enabled or 0
736 int mnt_context_is_sloppy(struct libmnt_context
*cxt
)
738 return cxt
->flags
& MNT_FL_SLOPPY
? 1 : 0;
742 * mnt_context_enable_fake:
743 * @cxt: mount context
744 * @enable: TRUE or FALSE
746 * Enable/disable fake mounting (see mount(8) man page, option -f).
748 * Returns: 0 on success, negative number in case of error.
750 int mnt_context_enable_fake(struct libmnt_context
*cxt
, int enable
)
752 return set_flag(cxt
, MNT_FL_FAKE
, enable
);
756 * mnt_context_is_fake:
757 * @cxt: mount context
759 * Returns: 1 if fake flag is enabled or 0
761 int mnt_context_is_fake(struct libmnt_context
*cxt
)
763 return cxt
->flags
& MNT_FL_FAKE
? 1 : 0;
767 * mnt_context_disable_mtab:
768 * @cxt: mount context
769 * @disable: TRUE or FALSE
771 * Disable/enable userspace mount table update (see mount(8) man page,
772 * option -n). Originally /etc/mtab, now /run/mount/utab.
774 * Returns: 0 on success, negative number in case of error.
776 int mnt_context_disable_mtab(struct libmnt_context
*cxt
, int disable
)
778 return set_flag(cxt
, MNT_FL_NOMTAB
, disable
);
782 * mnt_context_is_nomtab:
783 * @cxt: mount context
785 * Returns: 1 if no-mtab is enabled or 0
787 int mnt_context_is_nomtab(struct libmnt_context
*cxt
)
789 return cxt
->flags
& MNT_FL_NOMTAB
? 1 : 0;
793 * mnt_context_disable_swapmatch:
794 * @cxt: mount context
795 * @disable: TRUE or FALSE
797 * Disable/enable swap between source and target for mount(8) if only one path
800 * Returns: 0 on success, negative number in case of error.
802 int mnt_context_disable_swapmatch(struct libmnt_context
*cxt
, int disable
)
804 return set_flag(cxt
, MNT_FL_NOSWAPMATCH
, disable
);
808 * mnt_context_is_swapmatch:
809 * @cxt: mount context
811 * Returns: 1 if swap between source and target is allowed (default is 1) or 0.
813 int mnt_context_is_swapmatch(struct libmnt_context
*cxt
)
815 return cxt
->flags
& MNT_FL_NOSWAPMATCH
? 0 : 1;
819 * mnt_context_enable_force:
820 * @cxt: mount context
821 * @enable: TRUE or FALSE
823 * Enable/disable force umounting (see umount(8) man page, option -f).
825 * Returns: 0 on success, negative number in case of error.
827 int mnt_context_enable_force(struct libmnt_context
*cxt
, int enable
)
829 return set_flag(cxt
, MNT_FL_FORCE
, enable
);
833 * mnt_context_is_force
834 * @cxt: mount context
836 * Returns: 1 if force umounting flag is enabled or 0
838 int mnt_context_is_force(struct libmnt_context
*cxt
)
840 return cxt
->flags
& MNT_FL_FORCE
? 1 : 0;
844 * mnt_context_enable_verbose:
845 * @cxt: mount context
846 * @enable: TRUE or FALSE
848 * Enable/disable verbose output (TODO: not implemented yet)
850 * Returns: 0 on success, negative number in case of error.
852 int mnt_context_enable_verbose(struct libmnt_context
*cxt
, int enable
)
854 return set_flag(cxt
, MNT_FL_VERBOSE
, enable
);
858 * mnt_context_is_verbose
859 * @cxt: mount context
861 * Returns: 1 if verbose flag is enabled or 0
863 int mnt_context_is_verbose(struct libmnt_context
*cxt
)
865 return cxt
->flags
& MNT_FL_VERBOSE
? 1 : 0;
869 * mnt_context_enable_loopdel:
870 * @cxt: mount context
871 * @enable: TRUE or FALSE
873 * Enable/disable the loop delete (destroy) after umount (see umount(8), option -d)
875 * Returns: 0 on success, negative number in case of error.
877 int mnt_context_enable_loopdel(struct libmnt_context
*cxt
, int enable
)
879 return set_flag(cxt
, MNT_FL_LOOPDEL
, enable
);
883 * mnt_context_is_loopdel:
884 * @cxt: mount context
886 * Returns: 1 if loop device should be deleted after umount (umount -d) or 0.
888 int mnt_context_is_loopdel(struct libmnt_context
*cxt
)
890 return cxt
->flags
& MNT_FL_LOOPDEL
? 1 : 0;
894 * mnt_context_set_fs:
895 * @cxt: mount context
896 * @fs: filesystem description
898 * The mount context uses private @fs by default. This function can be used to
899 * overwrite the private @fs with an external instance. This function
900 * increments @fs reference counter (and decrement reference counter of the
903 * The @fs will be modified by mnt_context_set_{source,target,options,fstype}
904 * functions, If the @fs is NULL, then all current FS specific settings (source,
905 * target, etc., exclude spec) are reset.
907 * Returns: 0 on success, negative number in case of error.
909 int mnt_context_set_fs(struct libmnt_context
*cxt
, struct libmnt_fs
*fs
)
917 DBG(CXT
, ul_debugobj(cxt
, "setting new FS"));
921 struct libmnt_optlist
*ol
= mnt_context_get_optlist(cxt
);
928 mnt_optlist_set_optstr(ol
, mnt_fs_get_options(fs
), NULL
);
929 mnt_fs_follow_optlist(fs
, ol
);
934 mnt_fs_follow_optlist(cxt
->fs
, NULL
);
935 mnt_unref_fs(cxt
->fs
);
942 * mnt_context_get_fs:
943 * @cxt: mount context
945 * The FS contains the basic description of mountpoint, fs type and so on.
946 * Note that the FS is modified by mnt_context_set_{source,target,options,fstype}
949 * Returns: pointer to FS description or NULL in case of a calloc() error.
951 struct libmnt_fs
*mnt_context_get_fs(struct libmnt_context
*cxt
)
956 struct libmnt_optlist
*ol
= mnt_context_get_optlist(cxt
);
960 cxt
->fs
= mnt_new_fs();
964 mnt_fs_follow_optlist(cxt
->fs
, ol
);
970 * mnt_context_get_fs_userdata:
971 * @cxt: mount context
973 * Returns: pointer to userdata or NULL.
975 void *mnt_context_get_fs_userdata(struct libmnt_context
*cxt
)
977 return cxt
->fs
? mnt_fs_get_userdata(cxt
->fs
) : NULL
;
981 * mnt_context_get_fstab_userdata:
982 * @cxt: mount context
984 * Returns: pointer to userdata or NULL.
986 void *mnt_context_get_fstab_userdata(struct libmnt_context
*cxt
)
988 return cxt
->fstab
? mnt_table_get_userdata(cxt
->fstab
) : NULL
;
992 * mnt_context_get_mtab_userdata:
993 * @cxt: mount context
995 * The file /etc/mtab is no more used, @context points always to mountinfo
996 * (/proc/self/mountinfo). The function uses "mtab" in the name for backward
997 * compatibility only.
999 * Returns: pointer to userdata or NULL.
1001 void *mnt_context_get_mtab_userdata(struct libmnt_context
*cxt
)
1003 return cxt
->mountinfo
? mnt_table_get_userdata(cxt
->mountinfo
) : NULL
;
1007 * mnt_context_set_source:
1008 * @cxt: mount context
1009 * @source: mount source (device, directory, UUID, LABEL, ...)
1011 * Note that libmount does not interpret "nofail" (MNT_MS_NOFAIL)
1012 * mount option. The real return code is always returned, when
1013 * the device does not exist then it's usually MNT_ERR_NOSOURCE
1014 * from libmount or ENOENT, ENOTDIR, ENOTBLK, ENXIO from mount(2).
1016 * Returns: 0 on success, negative number in case of error.
1018 int mnt_context_set_source(struct libmnt_context
*cxt
, const char *source
)
1020 return mnt_fs_set_source(mnt_context_get_fs(cxt
), source
);
1024 * mnt_context_get_source:
1025 * @cxt: mount context
1027 * Returns: returns pointer or NULL in case of error or if not set.
1029 const char *mnt_context_get_source(struct libmnt_context
*cxt
)
1031 return mnt_fs_get_source(mnt_context_get_fs(cxt
));
1035 * mnt_context_set_target:
1036 * @cxt: mount context
1037 * @target: mountpoint
1039 * Returns: 0 on success, negative number in case of error.
1041 int mnt_context_set_target(struct libmnt_context
*cxt
, const char *target
)
1043 return mnt_fs_set_target(mnt_context_get_fs(cxt
), target
);
1047 * mnt_context_get_target:
1048 * @cxt: mount context
1050 * Returns: returns pointer or NULL in case of error or if not set.
1052 const char *mnt_context_get_target(struct libmnt_context
*cxt
)
1054 return mnt_fs_get_target(mnt_context_get_fs(cxt
));
1058 * mnt_context_set_target_prefix:
1059 * @cxt: mount context
1060 * @path: mountpoint prefix
1062 * Returns: 0 on success, negative number in case of error.
1064 int mnt_context_set_target_prefix(struct libmnt_context
*cxt
, const char *path
)
1075 free(cxt
->tgt_prefix
);
1076 cxt
->tgt_prefix
= p
;
1082 * mnt_context_get_target_prefix:
1083 * @cxt: mount context
1085 * Returns: returns pointer or NULL in case of error or if not set.
1087 const char *mnt_context_get_target_prefix(struct libmnt_context
*cxt
)
1089 return cxt
? cxt
->tgt_prefix
: NULL
;
1094 * mnt_context_set_fstype:
1095 * @cxt: mount context
1096 * @fstype: filesystem type
1098 * Note that the @fstype has to be a FS type. For patterns with
1099 * comma-separated list of filesystems or for the "nofs" notation, use
1100 * mnt_context_set_fstype_pattern().
1102 * Returns: 0 on success, negative number in case of error.
1104 int mnt_context_set_fstype(struct libmnt_context
*cxt
, const char *fstype
)
1106 return mnt_fs_set_fstype(mnt_context_get_fs(cxt
), fstype
);
1110 * mnt_context_get_fstype:
1111 * @cxt: mount context
1113 * Returns: pointer or NULL in case of error or if not set.
1115 const char *mnt_context_get_fstype(struct libmnt_context
*cxt
)
1117 return mnt_fs_get_fstype(mnt_context_get_fs(cxt
));
1120 struct libmnt_optlist
*mnt_context_get_optlist(struct libmnt_context
*cxt
)
1124 if (!cxt
->optlist
) {
1125 cxt
->optlist
= mnt_new_optlist();
1128 if (mnt_optlist_register_map(cxt
->optlist
, cxt
->map_linux
))
1130 if (mnt_optlist_register_map(cxt
->optlist
, cxt
->map_userspace
))
1134 return cxt
->optlist
;
1136 mnt_unref_optlist(cxt
->optlist
);
1141 * mnt_context_set_options:
1142 * @cxt: mount context
1143 * @optstr: comma delimited mount options
1145 * Note that MS_MOVE cannot be specified as "string". It's operation that
1146 * is no supported in fstab (etc.)
1148 * Returns: 0 on success, negative number in case of error.
1150 int mnt_context_set_options(struct libmnt_context
*cxt
, const char *optstr
)
1152 struct libmnt_optlist
*ls
= mnt_context_get_optlist(cxt
);
1156 return mnt_optlist_set_optstr(ls
, optstr
, NULL
);
1160 * mnt_context_append_options:
1161 * @cxt: mount context
1162 * @optstr: comma delimited mount options
1164 * Returns: 0 on success, negative number in case of error.
1166 int mnt_context_append_options(struct libmnt_context
*cxt
, const char *optstr
)
1168 struct libmnt_optlist
*ls
= mnt_context_get_optlist(cxt
);
1172 return mnt_optlist_append_optstr(ls
, optstr
, NULL
);
1176 * mnt_context_get_options:
1177 * @cxt: mount context
1179 * This function returns mount options set by mnt_context_set_options(),
1180 * mnt_context_append_options() or mnt_context_set_mflags();
1182 * Before v2.39 this function ignored options specified by flags (see
1183 * mnt_context_set_mflags()) before mnt_context_prepare_mount() call. Now this
1184 * function always returns all mount options.
1186 * Returns: pointer or NULL
1188 const char *mnt_context_get_options(struct libmnt_context
*cxt
)
1190 const char *str
= NULL
;
1192 if (cxt
->optlist
&& !mnt_optlist_is_empty(cxt
->optlist
))
1193 mnt_optlist_get_optstr(cxt
->optlist
, &str
, NULL
, 0);
1198 * mnt_context_set_fstype_pattern:
1199 * @cxt: mount context
1200 * @pattern: FS name pattern (or NULL to reset the current setting)
1202 * See mount(8), option -t.
1204 * Returns: 0 on success, negative number in case of error.
1206 int mnt_context_set_fstype_pattern(struct libmnt_context
*cxt
, const char *pattern
)
1213 p
= strdup(pattern
);
1217 free(cxt
->fstype_pattern
);
1218 cxt
->fstype_pattern
= p
;
1223 * mnt_context_set_options_pattern:
1224 * @cxt: mount context
1225 * @pattern: options pattern (or NULL to reset the current setting)
1227 * See mount(8), option -O.
1229 * Returns: 0 on success, negative number in case of error.
1231 int mnt_context_set_options_pattern(struct libmnt_context
*cxt
, const char *pattern
)
1238 p
= strdup(pattern
);
1242 free(cxt
->optstr_pattern
);
1243 cxt
->optstr_pattern
= p
;
1248 * mnt_context_set_fstab:
1249 * @cxt: mount context
1252 * The mount context reads /etc/fstab to the private struct libmnt_table by default.
1253 * This function can be used to overwrite the private fstab with an external
1256 * This function modify the @tb reference counter. This function does not set
1257 * the cache for the @tb. You have to explicitly call mnt_table_set_cache(tb,
1258 * mnt_context_get_cache(cxt));
1260 * The fstab is used read-only and is not modified, it should be possible to
1261 * share the fstab between more mount contexts (TODO: test it.)
1263 * If the @tb argument is NULL, then the current private fstab instance is
1266 * Returns: 0 on success, negative number in case of error.
1268 int mnt_context_set_fstab(struct libmnt_context
*cxt
, struct libmnt_table
*tb
)
1273 mnt_ref_table(tb
); /* new */
1274 mnt_unref_table(cxt
->fstab
); /* old */
1281 * mnt_context_get_fstab:
1282 * @cxt: mount context
1283 * @tb: returns fstab
1285 * See also mnt_table_parse_fstab() for more details about fstab.
1287 * Returns: 0 on success, negative number in case of error.
1289 int mnt_context_get_fstab(struct libmnt_context
*cxt
, struct libmnt_table
**tb
)
1291 struct libmnt_ns
*ns_old
;
1298 cxt
->fstab
= mnt_new_table();
1301 if (cxt
->table_errcb
)
1302 mnt_table_set_parser_errcb(cxt
->fstab
, cxt
->table_errcb
);
1304 ns_old
= mnt_context_switch_target_ns(cxt
);
1306 return -MNT_ERR_NAMESPACE
;
1308 mnt_table_set_cache(cxt
->fstab
, mnt_context_get_cache(cxt
));
1309 rc
= mnt_table_parse_fstab(cxt
->fstab
, NULL
);
1311 if (!mnt_context_switch_ns(cxt
, ns_old
))
1312 return -MNT_ERR_NAMESPACE
;
1323 int mnt_context_get_mountinfo(struct libmnt_context
*cxt
, struct libmnt_table
**tb
)
1326 struct libmnt_ns
*ns_old
= NULL
;
1330 if (!cxt
->mountinfo
) {
1331 ns_old
= mnt_context_switch_target_ns(cxt
);
1333 return -MNT_ERR_NAMESPACE
;
1335 context_init_paths(cxt
, 0);
1337 cxt
->mountinfo
= mnt_new_table();
1338 if (!cxt
->mountinfo
) {
1343 mnt_table_enable_noautofs(cxt
->mountinfo
, cxt
->noautofs
);
1345 if (cxt
->table_errcb
)
1346 mnt_table_set_parser_errcb(cxt
->mountinfo
, cxt
->table_errcb
);
1347 if (cxt
->table_fltrcb
)
1348 mnt_table_set_parser_fltrcb(cxt
->mountinfo
,
1350 cxt
->table_fltrcb_data
);
1352 mnt_table_set_cache(cxt
->mountinfo
, mnt_context_get_cache(cxt
));
1355 /* Read the table; it's empty, because this first mnt_context_get_mountinfo()
1356 * call, or because /proc was not accessible in previous calls */
1357 if (mnt_table_is_empty(cxt
->mountinfo
)) {
1359 ns_old
= mnt_context_switch_target_ns(cxt
);
1361 return -MNT_ERR_NAMESPACE
;
1364 rc
= __mnt_table_parse_mountinfo(cxt
->mountinfo
, NULL
, cxt
->utab
);
1370 *tb
= cxt
->mountinfo
;
1372 DBG(CXT
, ul_debugobj(cxt
, "mountinfo requested [nents=%d]",
1373 mnt_table_get_nents(cxt
->mountinfo
)));
1376 if (ns_old
&& !mnt_context_switch_ns(cxt
, ns_old
))
1377 return -MNT_ERR_NAMESPACE
;
1383 * mnt_context_get_mtab:
1384 * @cxt: mount context
1387 * Parse /proc/self/mountinfo mount table.
1389 * The file /etc/mtab is no more used, @context points always to mountinfo
1390 * (/proc/self/mountinfo). The function uses "mtab" in the name for backward
1391 * compatibility only.
1393 * See also mnt_table_parse_mtab() for more details about mountinfo. The
1394 * result will be deallocated by mnt_free_context(@cxt).
1396 * Returns: 0 on success, negative number in case of error.
1398 int mnt_context_get_mtab(struct libmnt_context
*cxt
, struct libmnt_table
**tb
)
1400 return mnt_context_get_mountinfo(cxt
, tb
);
1404 * Called by mountinfo parser to filter out entries, non-zero means that
1405 * an entry has to be filtered out.
1407 static int mountinfo_filter(struct libmnt_fs
*fs
, void *data
)
1411 if (mnt_fs_streq_target(fs
, data
))
1413 if (mnt_fs_streq_srcpath(fs
, data
))
1419 * The same like mnt_context_get_mountinfo(), but does not read all mountinfo
1420 * file, but only entries relevant for @tgt.
1422 int mnt_context_get_mountinfo_for_target(struct libmnt_context
*cxt
,
1423 struct libmnt_table
**mountinfo
,
1427 struct libmnt_cache
*cache
= NULL
;
1428 char *cn_tgt
= NULL
;
1430 struct libmnt_ns
*ns_old
;
1432 ns_old
= mnt_context_switch_target_ns(cxt
);
1434 return -MNT_ERR_NAMESPACE
;
1436 if (mnt_context_is_nocanonicalize(cxt
))
1437 mnt_context_set_tabfilter(cxt
, mountinfo_filter
, (void *) tgt
);
1439 else if (mnt_safe_stat(tgt
, &st
) == 0 && S_ISDIR(st
.st_mode
)) {
1440 cache
= mnt_context_get_cache(cxt
);
1441 cn_tgt
= mnt_resolve_path(tgt
, cache
);
1443 mnt_context_set_tabfilter(cxt
, mountinfo_filter
, cn_tgt
);
1446 rc
= mnt_context_get_mountinfo(cxt
, mountinfo
);
1447 mnt_context_set_tabfilter(cxt
, NULL
, NULL
);
1449 if (!mnt_context_switch_ns(cxt
, ns_old
))
1450 return -MNT_ERR_NAMESPACE
;
1452 if (cn_tgt
&& !cache
)
1459 * Allows to specify a filter for tab file entries. The filter is called by
1460 * the table parser. Currently used for utab only.
1462 int mnt_context_set_tabfilter(struct libmnt_context
*cxt
,
1463 int (*fltr
)(struct libmnt_fs
*, void *),
1469 cxt
->table_fltrcb
= fltr
;
1470 cxt
->table_fltrcb_data
= data
;
1473 mnt_table_set_parser_fltrcb(cxt
->mountinfo
,
1475 cxt
->table_fltrcb_data
);
1477 DBG(CXT
, ul_debugobj(cxt
, "tabfilter %s", fltr
? "ENABLED!" : "disabled"));
1482 * mnt_context_get_table:
1483 * @cxt: mount context
1484 * @filename: e.g. /proc/self/mountinfo
1485 * @tb: returns the table
1487 * This function allocates a new table and parses the @file. The parser error
1488 * callback and cache for tags and paths is set according to the @cxt setting.
1489 * See also mnt_table_parse_file().
1491 * It's strongly recommended to use the mnt_context_get_mtab() and
1492 * mnt_context_get_fstab() functions for mountinfo and fstab files. This function
1493 * does not care about LIBMOUNT_* env.variables and does not merge userspace
1496 * The result will NOT be deallocated by mnt_free_context(@cxt).
1498 * Returns: 0 on success, negative number in case of error.
1500 int mnt_context_get_table(struct libmnt_context
*cxt
,
1501 const char *filename
, struct libmnt_table
**tb
)
1504 struct libmnt_ns
*ns_old
;
1509 *tb
= mnt_new_table();
1513 if (cxt
->table_errcb
)
1514 mnt_table_set_parser_errcb(*tb
, cxt
->table_errcb
);
1516 ns_old
= mnt_context_switch_target_ns(cxt
);
1518 return -MNT_ERR_NAMESPACE
;
1520 rc
= mnt_table_parse_file(*tb
, filename
);
1523 mnt_unref_table(*tb
);
1527 mnt_table_set_cache(*tb
, mnt_context_get_cache(cxt
));
1530 if (!mnt_context_switch_ns(cxt
, ns_old
))
1531 return -MNT_ERR_NAMESPACE
;
1537 * mnt_context_set_tables_errcb
1538 * @cxt: mount context
1539 * @cb: pointer to callback function
1541 * The error callback is used for all tab files (e.g. mountinfo, fstab)
1542 * parsed within the context.
1544 * See also mnt_context_get_mtab(),
1545 * mnt_context_get_fstab(),
1546 * mnt_table_set_parser_errcb().
1548 * Returns: 0 on success, negative number in case of error.
1550 int mnt_context_set_tables_errcb(struct libmnt_context
*cxt
,
1551 int (*cb
)(struct libmnt_table
*tb
, const char *filename
, int line
))
1557 mnt_table_set_parser_errcb(cxt
->mountinfo
, cb
);
1559 mnt_table_set_parser_errcb(cxt
->fstab
, cb
);
1561 cxt
->table_errcb
= cb
;
1566 * mnt_context_set_cache:
1567 * @cxt: mount context
1568 * @cache: cache instance or NULL
1570 * The mount context maintains a private struct libmnt_cache by default. This
1571 * function can be used to overwrite the private cache with an external instance.
1572 * This function increments cache reference counter.
1574 * If the @cache argument is NULL, then the current cache instance is reset.
1575 * This function apply the cache to fstab and mountinfo instances (if already
1578 * The old cache instance reference counter is de-incremented.
1580 * Returns: 0 on success, negative number in case of error.
1582 int mnt_context_set_cache(struct libmnt_context
*cxt
, struct libmnt_cache
*cache
)
1587 mnt_ref_cache(cache
); /* new */
1588 mnt_unref_cache(cxt
->cache
); /* old */
1593 mnt_table_set_cache(cxt
->mountinfo
, cache
);
1595 mnt_table_set_cache(cxt
->fstab
, cache
);
1601 * mnt_context_get_cache
1602 * @cxt: mount context
1604 * See also mnt_context_set_cache().
1606 * Returns: pointer to cache or NULL if canonicalization is disabled.
1608 struct libmnt_cache
*mnt_context_get_cache(struct libmnt_context
*cxt
)
1610 if (!cxt
|| mnt_context_is_nocanonicalize(cxt
))
1614 struct libmnt_cache
*cache
= mnt_new_cache();
1615 mnt_context_set_cache(cxt
, cache
);
1616 mnt_unref_cache(cache
);
1622 * mnt_context_set_passwd_cb:
1623 * @cxt: mount context
1624 * @get: callback to get password
1625 * @release: callback to release (deallocate) password
1627 * Sets callbacks for encryption password (e.g encrypted loopdev). This
1628 * function is deprecated (encrypted loops are no longer supported).
1630 * Returns: 0 on success, negative number in case of error.
1632 int mnt_context_set_passwd_cb(struct libmnt_context
*cxt
,
1633 char *(*get
)(struct libmnt_context
*),
1634 void (*release
)(struct libmnt_context
*, char *))
1638 cxt
->pwd_get_cb
= get
;
1639 cxt
->pwd_release_cb
= release
;
1644 * mnt_context_get_lock:
1645 * @cxt: mount context
1647 * The libmount applications don't have to care about utab locking, but with a
1648 * small exception: the application has to be able to remove the lock file when
1649 * interrupted by signal or signals have to be ignored when the lock is locked.
1651 * The default behavior is to ignore all signals (except SIGALRM and
1652 * SIGTRAP for utab update) when the lock is locked. If this behavior
1653 * is unacceptable, then use:
1655 * lc = mnt_context_get_lock(cxt);
1657 * mnt_lock_block_signals(lc, FALSE);
1659 * and don't forget to call mnt_unlock_file(lc) before exit.
1661 * Returns: pointer to lock struct or NULL.
1663 struct libmnt_lock
*mnt_context_get_lock(struct libmnt_context
*cxt
)
1666 * DON'T call this function within libmount, it will always allocate
1667 * the lock. The mnt_update_* functions are able to allocate the lock
1668 * only when utab update is really necessary.
1670 if (!cxt
|| mnt_context_is_nomtab(cxt
))
1674 cxt
->lock
= mnt_new_lock(
1675 mnt_context_get_writable_tabpath(cxt
), 0);
1677 mnt_lock_block_signals(cxt
->lock
, TRUE
);
1683 * mnt_context_set_mflags:
1684 * @cxt: mount context
1685 * @flags: mount(2) flags (MS_* flags)
1687 * Sets mount flags (see mount(2) man page).
1689 * Note that order of mount options (strings) and flags matter if you mix
1690 * mnt_context_append_options() and mnt_context_set_mflags().
1692 * Be careful if use MS_REC flag -- this is flags is generic for
1693 * all mask. In this case is better to use options string where
1694 * mount options are independent and nothign is applied to all options.
1696 * Returns: 0 on success, negative number in case of error.
1698 int mnt_context_set_mflags(struct libmnt_context
*cxt
, unsigned long flags
)
1700 struct libmnt_optlist
*ls
= mnt_context_get_optlist(cxt
);
1705 return mnt_optlist_set_flags(ls
, flags
, cxt
->map_linux
);
1709 * mnt_context_get_mflags:
1710 * @cxt: mount context
1711 * @flags: returns MS_* mount flags
1713 * Converts mount options string to MS_* flags and bitwise-OR the result with
1714 * the already defined flags (see mnt_context_set_mflags()).
1716 * Returns: 0 on success, negative number in case of error.
1718 int mnt_context_get_mflags(struct libmnt_context
*cxt
, unsigned long *flags
)
1720 struct libmnt_optlist
*ls
= mnt_context_get_optlist(cxt
);
1725 return mnt_optlist_get_flags(ls
, flags
, cxt
->map_linux
, 0);
1729 * mnt_context_set_user_mflags:
1730 * @cxt: mount context
1731 * @flags: mount(2) flags (MNT_MS_* flags, e.g. MNT_MS_LOOP)
1733 * Sets userspace mount flags.
1735 * See also notes for mnt_context_set_mflags().
1737 * Returns: 0 on success, negative number in case of error.
1739 int mnt_context_set_user_mflags(struct libmnt_context
*cxt
, unsigned long flags
)
1741 struct libmnt_optlist
*ls
= mnt_context_get_optlist(cxt
);
1746 return mnt_optlist_set_flags(ls
, flags
, cxt
->map_userspace
);
1750 * mnt_context_get_user_mflags:
1751 * @cxt: mount context
1752 * @flags: returns mount flags
1754 * Converts mount options string to MNT_MS_* flags and bitwise-OR the result
1755 * with the already defined flags (see mnt_context_set_user_mflags()).
1757 * Returns: 0 on success, negative number in case of error.
1759 int mnt_context_get_user_mflags(struct libmnt_context
*cxt
, unsigned long *flags
)
1761 struct libmnt_optlist
*ls
= mnt_context_get_optlist(cxt
);
1766 return mnt_optlist_get_flags(ls
, flags
, cxt
->map_userspace
, 0);
1770 * mnt_context_set_mountdata:
1771 * @cxt: mount context
1772 * @data: mount(2) data
1774 * The mount context generates mountdata from mount options by default. This
1775 * function can be used to overwrite this behavior, and @data will be used instead
1778 * The libmount does not deallocate the data by mnt_free_context(). Note that
1779 * NULL is also valid mount data.
1781 * Returns: 0 on success, negative number in case of error.
1783 int mnt_context_set_mountdata(struct libmnt_context
*cxt
, void *data
)
1787 cxt
->mountdata
= data
;
1788 cxt
->flags
|= MNT_FL_MOUNTDATA
;
1793 * Translates LABEL/UUID/path to mountable path
1795 int mnt_context_prepare_srcpath(struct libmnt_context
*cxt
)
1797 const char *path
= NULL
;
1798 struct libmnt_cache
*cache
;
1799 const char *t
, *v
, *src
, *type
;
1801 struct libmnt_ns
*ns_old
;
1802 struct libmnt_optlist
*ol
;
1806 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
1808 DBG(CXT
, ul_debugobj(cxt
, "--> preparing source path"));
1810 src
= mnt_fs_get_source(cxt
->fs
);
1812 if (!src
&& mnt_context_propagation_only(cxt
))
1813 /* mount --make-{shared,private,...} */
1814 return mnt_fs_set_source(cxt
->fs
, "none");
1816 /* ignore filesystems without source or filesystems
1817 * where the source is a quasi-path (//foo/bar)
1819 if (!src
|| mnt_fs_is_netfs(cxt
->fs
))
1822 /* ZFS source is always "dataset", not a real path */
1823 type
= mnt_fs_get_fstype(cxt
->fs
);
1824 if (type
&& strcmp(type
, "zfs") == 0)
1827 DBG(CXT
, ul_debugobj(cxt
, "srcpath '%s'", src
));
1829 ns_old
= mnt_context_switch_target_ns(cxt
);
1831 return -MNT_ERR_NAMESPACE
;
1833 cache
= mnt_context_get_cache(cxt
);
1835 if (!mnt_fs_get_tag(cxt
->fs
, &t
, &v
)) {
1837 * Source is TAG (evaluate)
1840 path
= mnt_resolve_tag(t
, v
, cache
);
1842 rc
= path
? mnt_fs_set_source(cxt
->fs
, path
) : -MNT_ERR_NOSOURCE
;
1844 } else if (cache
&& !mnt_fs_is_pseudofs(cxt
->fs
)) {
1846 * Source is PATH (canonicalize)
1848 path
= mnt_resolve_path(src
, cache
);
1849 if (path
&& strcmp(path
, src
) != 0)
1850 rc
= mnt_fs_set_source(cxt
->fs
, path
);
1854 DBG(CXT
, ul_debugobj(cxt
, "failed to prepare srcpath [rc=%d]", rc
));
1861 ol
= mnt_context_get_optlist(cxt
);
1865 if (mnt_optlist_is_bind(ol
)
1866 || mnt_optlist_is_move(ol
)
1867 || mnt_optlist_is_remount(ol
)
1868 || mnt_fs_is_pseudofs(cxt
->fs
)) {
1869 DBG(CXT
, ul_debugobj(cxt
, "REMOUNT/BIND/MOVE/pseudo FS source: %s", path
));
1873 rc
= mnt_context_call_hooks(cxt
, MNT_STAGE_PREP_SOURCE
);
1877 DBG(CXT
, ul_debugobj(cxt
, "final srcpath '%s'",
1878 mnt_fs_get_source(cxt
->fs
)));
1881 if (!mnt_context_switch_ns(cxt
, ns_old
))
1882 return -MNT_ERR_NAMESPACE
;
1886 /* Guess type, but not set to cxt->fs, always use free() for the result. It's
1887 * no error when we're not able to guess a filesystem type. Note that error
1888 * does not mean that result in @type is NULL.
1890 int mnt_context_guess_srcpath_fstype(struct libmnt_context
*cxt
, char **type
)
1893 struct libmnt_ns
*ns_old
;
1901 dev
= mnt_fs_get_srcpath(cxt
->fs
);
1905 ns_old
= mnt_context_switch_target_ns(cxt
);
1907 return -MNT_ERR_NAMESPACE
;
1909 if (access(dev
, F_OK
) == 0) {
1910 struct libmnt_cache
*cache
= mnt_context_get_cache(cxt
);
1913 *type
= mnt_get_fstype(dev
, &ambi
, cache
);
1915 rc
= -MNT_ERR_AMBIFS
;
1917 if (cache
&& *type
) {
1918 *type
= strdup(*type
);
1923 DBG(CXT
, ul_debugobj(cxt
, "access(%s) failed [%m]", dev
));
1924 if (strchr(dev
, ':') != NULL
) {
1925 *type
= strdup("nfs");
1928 } else if (!strncmp(dev
, "//", 2)) {
1929 *type
= strdup("cifs");
1935 if (!mnt_context_switch_ns(cxt
, ns_old
))
1936 return -MNT_ERR_NAMESPACE
;
1938 if (rc
== 0 && *type
) {
1939 struct libmnt_optlist
*ol
= mnt_context_get_optlist(cxt
);
1940 struct libmnt_opt
*opt
;
1941 const char *allowed
;
1946 opt
= mnt_optlist_get_named(ol
,
1947 "X-mount.auto-fstypes", cxt
->map_userspace
);
1950 && (allowed
= mnt_opt_get_value(opt
))
1951 && !match_fstype(*type
, allowed
)) {
1952 DBG(CXT
, ul_debugobj(cxt
, "%s is not allowed by auto-fstypes=%s",
1956 rc
= -MNT_ERR_NOFSTYPE
;
1964 * It's usually no error when we're not able to detect the filesystem type -- we
1965 * will try to use the types from /{etc,proc}/filesystems.
1967 int mnt_context_guess_fstype(struct libmnt_context
*cxt
)
1969 struct libmnt_optlist
*ol
;
1975 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
1977 DBG(CXT
, ul_debugobj(cxt
, "--> preparing fstype"));
1979 ol
= mnt_context_get_optlist(cxt
);
1983 if (mnt_optlist_is_bind(ol
)
1984 || mnt_optlist_is_move(ol
)
1985 || mnt_context_propagation_only(cxt
))
1988 type
= (char *) mnt_fs_get_fstype(cxt
->fs
);
1989 if (type
&& !strcmp(type
, "auto")) {
1990 mnt_fs_set_fstype(cxt
->fs
, NULL
);
1996 if (mnt_optlist_is_remount(ol
))
1998 if (cxt
->fstype_pattern
)
2001 rc
= mnt_context_guess_srcpath_fstype(cxt
, &type
);
2002 if (rc
== 0 && type
)
2003 __mnt_fs_set_fstype_ptr(cxt
->fs
, type
);
2007 DBG(CXT
, ul_debugobj(cxt
, "FS type: %s [rc=%d]",
2008 mnt_fs_get_fstype(cxt
->fs
), rc
));
2011 return mnt_fs_set_fstype(cxt
->fs
, "none");
2015 * The default is to use fstype from cxt->fs, this could be overwritten by
2016 * @type. The @act is MNT_ACT_{MOUNT,UMOUNT}.
2018 * Returns: 0 on success or negative number in case of error. Note that success
2019 * does not mean that there is any usable helper, you have to check cxt->helper.
2021 int mnt_context_prepare_helper(struct libmnt_context
*cxt
, const char *name
,
2024 char search_path
[] = FS_SEARCH_PATH
; /* from config.h */
2025 char *p
= NULL
, *path
;
2026 struct libmnt_ns
*ns_old
;
2031 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
2033 DBG(CXT
, ul_debugobj(cxt
, "checking for helper"));
2041 type
= mnt_fs_get_fstype(cxt
->fs
);
2043 if (type
&& strchr(type
, ','))
2044 return 0; /* type is fstype pattern */
2046 if (mnt_context_is_nohelpers(cxt
)
2048 || !strcmp(type
, "none")
2049 || strstr(type
, "/..") /* don't try to smuggle path */
2050 || mnt_fs_is_swaparea(cxt
->fs
))
2053 ns_old
= mnt_context_switch_origin_ns(cxt
);
2055 return -MNT_ERR_NAMESPACE
;
2057 /* Ignore errors when search in $PATH and do not modify @rc
2059 path
= strtok_r(search_path
, ":", &p
);
2061 char helper
[PATH_MAX
];
2064 len
= snprintf(helper
, sizeof(helper
), "%s/%s.%s",
2066 path
= strtok_r(NULL
, ":", &p
);
2068 if (len
< 0 || (size_t) len
>= sizeof(helper
))
2071 found
= mnt_is_path(helper
);
2072 if (!found
&& strchr(type
, '.')) {
2073 /* If type ends with ".subtype" try without it */
2074 char *hs
= strrchr(helper
, '.');
2077 found
= mnt_is_path(helper
);
2080 DBG(CXT
, ul_debugobj(cxt
, "%-25s ... %s", helper
,
2081 found
? "found" : "not found"));
2086 rc
= strdup_to_struct_member(cxt
, helper
, helper
);
2090 if (!mnt_context_switch_ns(cxt
, ns_old
))
2091 rc
= -MNT_ERR_NAMESPACE
;
2093 /* make sure helper is not set on error */
2101 /* stop differentiate between options defined by flags and strings */
2102 int mnt_context_merge_mflags(struct libmnt_context
*cxt
)
2104 struct libmnt_optlist
*ls
= mnt_context_get_optlist(cxt
);
2109 /* TODO: optlist returns always flags as merged, so
2110 * MNT_FL_MOUNTFLAGS_MERGED is unncessary anymore
2112 cxt
->flags
|= MNT_FL_MOUNTFLAGS_MERGED
;
2113 return mnt_optlist_merge_opts(ls
);
2117 * Prepare /run/mount/utab
2119 int mnt_context_prepare_update(struct libmnt_context
*cxt
)
2122 const char *target
, *name
;
2123 unsigned long flags
= 0;
2127 assert(cxt
->action
);
2128 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
2130 DBG(CXT
, ul_debugobj(cxt
, "--> prepare update"));
2132 if (mnt_context_propagation_only(cxt
)) {
2133 DBG(CXT
, ul_debugobj(cxt
, "skip update: only MS_PROPAGATION"));
2137 target
= mnt_fs_get_target(cxt
->fs
);
2139 if (cxt
->action
== MNT_ACT_UMOUNT
&& target
&& !strcmp(target
, "/")) {
2140 DBG(CXT
, ul_debugobj(cxt
, "root umount: setting NOMTAB"));
2141 mnt_context_disable_mtab(cxt
, TRUE
);
2143 if (mnt_context_is_nomtab(cxt
)) {
2144 DBG(CXT
, ul_debugobj(cxt
, "skip update: NOMTAB flag"));
2147 name
= mnt_context_get_writable_tabpath(cxt
);
2149 DBG(CXT
, ul_debugobj(cxt
, "skip update: no writable destination"));
2152 /* 0 = success, 1 = not called yet */
2153 if (cxt
->syscall_status
!= 1 && cxt
->syscall_status
!= 0) {
2154 DBG(CXT
, ul_debugobj(cxt
,
2155 "skip update: syscall failed [status=%d]",
2156 cxt
->syscall_status
));
2161 if (cxt
->action
== MNT_ACT_UMOUNT
&& is_file_empty(name
)) {
2162 DBG(CXT
, ul_debugobj(cxt
, "skip update: umount, no table"));
2166 cxt
->update
= mnt_new_update();
2170 mnt_update_set_filename(cxt
->update
, name
);
2173 mnt_context_get_mflags(cxt
, &flags
);
2175 if (cxt
->action
== MNT_ACT_UMOUNT
)
2176 rc
= mnt_update_set_fs(cxt
->update
, flags
,
2177 mnt_context_get_target(cxt
), NULL
);
2179 rc
= mnt_update_set_fs(cxt
->update
, flags
,
2182 return rc
< 0 ? rc
: 0;
2185 int mnt_context_update_tabs(struct libmnt_context
*cxt
)
2188 struct libmnt_ns
*ns_old
;
2192 if (mnt_context_is_nomtab(cxt
)) {
2193 DBG(CXT
, ul_debugobj(cxt
, "don't update: NOMTAB flag"));
2196 if (!cxt
->update
|| !mnt_update_is_ready(cxt
->update
)) {
2197 DBG(CXT
, ul_debugobj(cxt
, "don't update: no update prepared"));
2201 ns_old
= mnt_context_switch_target_ns(cxt
);
2203 return -MNT_ERR_NAMESPACE
;
2205 /* check utab update when external helper executed */
2206 if (mnt_context_helper_executed(cxt
)
2207 && mnt_context_get_helper_status(cxt
) == 0
2208 && mnt_context_utab_writable(cxt
)) {
2210 if (mnt_update_already_done(cxt
->update
, cxt
->lock
)) {
2211 DBG(CXT
, ul_debugobj(cxt
, "don't update: error evaluate or already updated"));
2214 } else if (cxt
->helper
) {
2215 DBG(CXT
, ul_debugobj(cxt
, "don't update: external helper"));
2219 if (cxt
->syscall_status
!= 0
2220 && !(mnt_context_helper_executed(cxt
) &&
2221 mnt_context_get_helper_status(cxt
) == 0)) {
2223 DBG(CXT
, ul_debugobj(cxt
, "don't update: syscall/helper failed/not called"));
2227 rc
= mnt_update_table(cxt
->update
, cxt
->lock
);
2230 if (!mnt_context_switch_ns(cxt
, ns_old
))
2231 return -MNT_ERR_NAMESPACE
;
2235 /* apply @fs to @cxt;
2237 * @mflags are mount flags as specified on command-line -- used only to save
2238 * MS_RDONLY which is allowed for non-root users.
2240 static int apply_fs(struct libmnt_context
*cxt
, struct libmnt_fs
*fs
, unsigned long mflags
)
2242 struct libmnt_optlist
*ls
;
2247 if (!cxt
->optsmode
) {
2248 if (mnt_context_is_restricted(cxt
)) {
2249 DBG(CXT
, ul_debugobj(cxt
, "force fstab usage for non-root users!"));
2250 cxt
->optsmode
= MNT_OMODE_USER
;
2252 DBG(CXT
, ul_debugobj(cxt
, "use default optsmode"));
2253 cxt
->optsmode
= MNT_OMODE_AUTO
;
2258 if (!mnt_context_get_fs(cxt
))
2261 DBG(CXT
, ul_debugobj(cxt
, "apply entry:"));
2262 DBG(CXT
, mnt_fs_print_debug(fs
, stderr
));
2263 DBG(CXT
, ul_debugobj(cxt
, "OPTSMODE (opt-part): ignore=%d, append=%d, prepend=%d, replace=%d",
2264 cxt
->optsmode
& MNT_OMODE_IGNORE
? 1 : 0,
2265 cxt
->optsmode
& MNT_OMODE_APPEND
? 1 : 0,
2266 cxt
->optsmode
& MNT_OMODE_PREPEND
? 1 : 0,
2267 cxt
->optsmode
& MNT_OMODE_REPLACE
? 1 : 0));
2269 /* copy from fs to our FS description
2271 rc
= mnt_fs_set_source(cxt
->fs
, mnt_fs_get_source(fs
));
2273 rc
= mnt_fs_set_target(cxt
->fs
, mnt_fs_get_target(fs
));
2275 if (!rc
&& !mnt_fs_get_fstype(cxt
->fs
))
2276 rc
= mnt_fs_set_fstype(cxt
->fs
, mnt_fs_get_fstype(fs
));
2278 if (!rc
&& !mnt_fs_get_root(cxt
->fs
) && mnt_fs_get_root(fs
))
2279 rc
= mnt_fs_set_root(cxt
->fs
, mnt_fs_get_root(fs
));
2284 ls
= mnt_context_get_optlist(cxt
);
2290 if (cxt
->optsmode
& MNT_OMODE_IGNORE
)
2292 else if (cxt
->optsmode
& MNT_OMODE_REPLACE
) {
2293 rc
= mnt_optlist_set_optstr(ls
, mnt_fs_get_options(fs
), NULL
);
2295 /* mount --read-only for non-root users is allowed */
2296 if (rc
== 0 && (mflags
& MS_RDONLY
)
2297 && mnt_context_is_restricted(cxt
)
2298 && cxt
->optsmode
== MNT_OMODE_USER
)
2299 rc
= mnt_optlist_append_optstr(ls
, "ro", NULL
);
2301 else if (cxt
->optsmode
& MNT_OMODE_APPEND
)
2302 rc
= mnt_optlist_append_optstr(ls
, mnt_fs_get_options(fs
), NULL
);
2304 else if (cxt
->optsmode
& MNT_OMODE_PREPEND
)
2305 rc
= mnt_optlist_prepend_optstr(ls
, mnt_fs_get_options(fs
), NULL
);
2308 cxt
->flags
|= MNT_FL_TAB_APPLIED
;
2311 DBG(CXT
, ul_debugobj(cxt
, "final entry [rc=%d]", rc
));
2312 DBG(CXT
, mnt_fs_print_debug(cxt
->fs
, stderr
));
2317 static int apply_table(struct libmnt_context
*cxt
, struct libmnt_table
*tb
,
2318 int direction
, unsigned long mflags
)
2320 struct libmnt_fs
*fs
= NULL
;
2321 const char *src
, *tgt
;
2326 src
= mnt_fs_get_source(cxt
->fs
);
2327 tgt
= mnt_fs_get_target(cxt
->fs
);
2330 fs
= mnt_table_find_pair(tb
, src
, tgt
, direction
);
2333 fs
= mnt_table_find_source(tb
, src
, direction
);
2335 fs
= mnt_table_find_target(tb
, tgt
, direction
);
2337 if (!fs
&& mnt_context_is_swapmatch(cxt
)) {
2338 /* swap source and target (if @src is not LABEL/UUID),
2343 * the path could be a mountpoint as well as a source (for
2344 * example bind mount, symlink to a device, ...).
2346 if (src
&& !mnt_fs_get_tag(cxt
->fs
, NULL
, NULL
))
2347 fs
= mnt_table_find_target(tb
, src
, direction
);
2349 fs
= mnt_table_find_source(tb
, tgt
, direction
);
2354 return -MNT_ERR_NOFSTAB
; /* not found */
2356 return apply_fs(cxt
, fs
, mflags
);
2359 /* apply @fs to @cxt -- use mnt_context_apply_fstab() if not sure
2361 int mnt_context_apply_fs(struct libmnt_context
*cxt
, struct libmnt_fs
*fs
)
2363 return apply_fs(cxt
, fs
, 0);
2367 * mnt_context_apply_fstab:
2368 * @cxt: mount context
2370 * This function is optional.
2372 * Returns: 0 on success, negative number in case of error.
2374 int mnt_context_apply_fstab(struct libmnt_context
*cxt
)
2376 int rc
= -1, isremount
= 0, iscmdbind
= 0;
2377 struct libmnt_ns
*ns_old
;
2378 struct libmnt_table
*tab
= NULL
;
2379 const char *src
= NULL
, *tgt
= NULL
;
2380 unsigned long mflags
= 0;
2382 if (!cxt
|| !cxt
->fs
)
2385 if (mnt_context_tab_applied(cxt
)) { /* already applied */
2386 DBG(CXT
, ul_debugobj(cxt
, "fstab already applied -- skip"));
2390 if (mnt_context_is_restricted(cxt
)) {
2391 DBG(CXT
, ul_debugobj(cxt
, "force fstab usage for non-root users!"));
2392 cxt
->optsmode
= MNT_OMODE_USER
;
2393 } else if (cxt
->optsmode
== 0) {
2394 DBG(CXT
, ul_debugobj(cxt
, "use default optsmode"));
2395 cxt
->optsmode
= MNT_OMODE_AUTO
;
2396 } else if (cxt
->optsmode
& MNT_OMODE_NOTAB
) {
2397 cxt
->optsmode
&= ~MNT_OMODE_FSTAB
;
2398 cxt
->optsmode
&= ~MNT_OMODE_MTAB
;
2399 cxt
->optsmode
&= ~MNT_OMODE_FORCE
;
2402 if (mnt_context_get_mflags(cxt
, &mflags
) == 0) {
2403 isremount
= !!(mflags
& MS_REMOUNT
);
2404 iscmdbind
= !!(mflags
& MS_BIND
);
2408 src
= mnt_fs_get_source(cxt
->fs
);
2409 tgt
= mnt_fs_get_target(cxt
->fs
);
2412 DBG(CXT
, ul_debugobj(cxt
, "OPTSMODE (file-part): force=%d, fstab=%d, mtab=%d",
2413 cxt
->optsmode
& MNT_OMODE_FORCE
? 1 : 0,
2414 cxt
->optsmode
& MNT_OMODE_FSTAB
? 1 : 0,
2415 cxt
->optsmode
& MNT_OMODE_MTAB
? 1 : 0));
2417 /* fstab is not required if source and target are specified */
2418 if (src
&& tgt
&& !(cxt
->optsmode
& MNT_OMODE_FORCE
)) {
2419 DBG(CXT
, ul_debugobj(cxt
, "fstab not required -- skip"));
2424 && !(cxt
->optsmode
& MNT_OMODE_FSTAB
)
2425 && !(cxt
->optsmode
& MNT_OMODE_MTAB
)) {
2426 DBG(CXT
, ul_debugobj(cxt
, "only target; fstab/mtab not required "
2427 "-- skip, probably MS_PROPAGATION"));
2431 /* let's initialize cxt->fs */
2432 ignore_result( mnt_context_get_fs(cxt
) );
2434 ns_old
= mnt_context_switch_target_ns(cxt
);
2436 return -MNT_ERR_NAMESPACE
;
2439 if (cxt
->optsmode
& MNT_OMODE_FSTAB
) {
2440 DBG(CXT
, ul_debugobj(cxt
, "trying to apply fstab (src=%s, target=%s)", src
, tgt
));
2441 rc
= mnt_context_get_fstab(cxt
, &tab
);
2443 rc
= apply_table(cxt
, tab
, MNT_ITER_FORWARD
, mflags
);
2447 if (rc
< 0 && (cxt
->optsmode
& MNT_OMODE_MTAB
)
2448 && (isremount
|| cxt
->action
== MNT_ACT_UMOUNT
)) {
2449 DBG(CXT
, ul_debugobj(cxt
, "trying to apply mountinfo (src=%s, target=%s)", src
, tgt
));
2451 rc
= mnt_context_get_mountinfo_for_target(cxt
, &tab
, tgt
);
2453 rc
= mnt_context_get_mountinfo(cxt
, &tab
);
2455 rc
= apply_table(cxt
, tab
, MNT_ITER_BACKWARD
, mflags
);
2458 if (!mnt_context_switch_ns(cxt
, ns_old
))
2459 return -MNT_ERR_NAMESPACE
;
2462 if (!mnt_context_is_restricted(cxt
)
2465 DBG(CXT
, ul_debugobj(cxt
, "only target; ignore missing mountinfo entry on remount"));
2469 DBG(CXT
, ul_debugobj(cxt
, "failed to find entry in fstab/mountinfo [rc=%d]: %m", rc
));
2471 /* force to "not found in fstab/mountinfo" error, the details why
2472 * not found are not so important and may be misinterpreted by
2473 * applications... */
2474 rc
= -MNT_ERR_NOFSTAB
;
2477 } else if (isremount
&& !iscmdbind
&& cxt
->optlist
) {
2479 /* ignore "bind" on remount when the flag is read from fstab */
2480 mnt_optlist_remove_named(cxt
->optlist
, "bind", NULL
);
2486 * mnt_context_tab_applied:
2487 * @cxt: mount context
2489 * Returns: 1 if fstab (or mountinfo) has been applied to the context, or 0.
2491 int mnt_context_tab_applied(struct libmnt_context
*cxt
)
2493 return cxt
->flags
& MNT_FL_TAB_APPLIED
;
2497 * This is not a public function!
2499 * Returns 1 if *only propagation flags* change is requested.
2501 int mnt_context_propagation_only(struct libmnt_context
*cxt
)
2503 struct libmnt_optlist
*ls
;
2505 if (cxt
->action
!= MNT_ACT_MOUNT
)
2507 if (cxt
->mountdata
|| cxt
->fs
== NULL
)
2509 if (cxt
->fs
->fstype
&& strcmp(cxt
->fs
->fstype
, "none") != 0)
2511 if (cxt
->fs
->source
&& strcmp(cxt
->fs
->source
, "none") != 0)
2514 ls
= mnt_context_get_optlist(cxt
);
2515 return ls
? mnt_optlist_is_propagation_only(ls
) : 0;
2519 * mnt_context_get_status:
2520 * @cxt: mount context
2522 * Global libmount status.
2524 * The real exit code of the mount.type helper has to be tested by
2525 * mnt_context_get_helper_status(). The mnt_context_get_status() only informs
2526 * that exec() has been successful.
2528 * Returns: 1 if mount.type or mount(2) syscall has been successfully called.
2530 int mnt_context_get_status(struct libmnt_context
*cxt
)
2532 return !cxt
->syscall_status
|| !cxt
->helper_exec_status
;
2536 * mnt_context_helper_executed:
2537 * @cxt: mount context
2539 * Returns: 1 if mount.type helper has been executed, or 0.
2541 int mnt_context_helper_executed(struct libmnt_context
*cxt
)
2543 return cxt
->helper_exec_status
!= 1;
2547 * mnt_context_get_helper_status:
2548 * @cxt: mount context
2550 * Return: mount.type helper exit status, result is reliable only if
2551 * mnt_context_helper_executed() returns 1.
2553 int mnt_context_get_helper_status(struct libmnt_context
*cxt
)
2555 return cxt
->helper_status
;
2559 * mnt_context_syscall_called:
2560 * @cxt: mount context
2562 * Returns: 1 if mount(2) syscall has been called, or 0.
2564 int mnt_context_syscall_called(struct libmnt_context
*cxt
)
2566 return cxt
->syscall_status
!= 1;
2570 * mnt_context_get_syscall_errno:
2571 * @cxt: mount context
2573 * The result from this function is reliable only if
2574 * mnt_context_syscall_called() returns 1.
2576 * Returns: mount(2) errno if the syscall failed or 0.
2578 int mnt_context_get_syscall_errno(struct libmnt_context
*cxt
)
2580 if (cxt
->syscall_status
< 0)
2581 return -cxt
->syscall_status
;
2586 * mnt_context_set_syscall_status:
2587 * @cxt: mount context
2588 * @status: mount(2) status
2590 * The @status should be 0 on success, or negative number on error (-errno).
2592 * This function should only be used if the [u]mount(2) syscall is NOT called by
2595 * Returns: 0 or negative number in case of error.
2597 int mnt_context_set_syscall_status(struct libmnt_context
*cxt
, int status
)
2602 DBG(CXT
, ul_debugobj(cxt
, "syscall status set to: %d", status
));
2603 cxt
->syscall_status
= status
;
2608 * mnt_context_strerror
2611 * @bufsiz: size of the buffer
2613 * Not implemented, deprecated in favor or mnt_context_get_excode().
2615 * Returns: 0 or negative number in case of error.
2617 int mnt_context_strerror(struct libmnt_context
*cxt
__attribute__((__unused__
)),
2618 char *buf
__attribute__((__unused__
)),
2619 size_t bufsiz
__attribute__((__unused__
)))
2621 /* TODO: based on cxt->syscall_errno or cxt->helper_status */
2626 * mnt_context_enable_noautofs:
2628 * @ignore: ignore or don't ignore
2630 * Enable/disable ignore autofs mount table entries on reading the
2631 * mount table. Only effective if the "ignore" mount option is being
2632 * used for autofs mounts (such as if automount(8) has been configured
2635 int mnt_context_enable_noautofs(struct libmnt_context
*cxt
, int ignore
)
2639 cxt
->noautofs
= ignore
? 1 : 0;
2643 int mnt_context_get_generic_excode(int rc
, char *buf
, size_t bufsz
, const char *fmt
, ...)
2648 return MNT_EX_SUCCESS
;
2652 /* we need to support "%m" */
2653 errno
= rc
< 0 ? -rc
: rc
;
2655 if (buf
&& bufsz
&& vsnprintf(buf
, bufsz
, fmt
, va
) < 0)
2675 * mnt_context_get_excode:
2677 * @rc: return code of the previous operation
2678 * @buf: buffer to print error message (optional)
2679 * @bufsz: size of the buffer
2681 * This function analyzes context, [u]mount syscall and external helper status
2682 * and @mntrc and generates unified return code (see MNT_EX_*) as expected
2683 * from mount(8) or umount(8).
2685 * If the external helper (e.g. /sbin/mount.type) has been executed than it
2686 * returns status from wait() of the helper. It's not libmount fail if helper
2687 * returns some crazy undocumented codes... See mnt_context_helper_executed()
2688 * and mnt_context_get_helper_status(). Note that mount(8) and umount(8) utils
2689 * always return code from helper without extra care about it.
2691 * The current implementation does not read error message from external
2694 * If the argument @buf is not NULL then error message is generated (if
2697 * The @mntrc is usually return code from mnt_context_mount(),
2698 * mnt_context_umount(), or 'mntrc' as returned by mnt_context_next_mount().
2702 * Returns: MNT_EX_* codes.
2704 int mnt_context_get_excode(
2705 struct libmnt_context
*cxt
,
2711 *buf
= '\0'; /* for sure */
2713 if (!cxt
->enabled_textdomain
) {
2714 bindtextdomain(LIBMOUNT_TEXTDOMAIN
, LOCALEDIR
);
2715 cxt
->enabled_textdomain
= 1;
2719 switch (cxt
->action
) {
2721 rc
= mnt_context_get_mount_excode(cxt
, rc
, buf
, bufsz
);
2723 case MNT_ACT_UMOUNT
:
2724 rc
= mnt_context_get_umount_excode(cxt
, rc
, buf
, bufsz
);
2728 rc
= mnt_context_get_generic_excode(rc
, buf
, bufsz
,
2729 _("operation failed: %m"));
2731 rc
= MNT_EX_SUCCESS
;
2735 DBG(CXT
, ul_debugobj(cxt
, "excode: rc=%d message=\"%s\"", rc
,
2736 buf
? buf
: "<no-message>"));
2742 * mnt_context_init_helper
2743 * @cxt: mount context
2744 * @action: MNT_ACT_{UMOUNT,MOUNT}
2745 * @flags: not used now
2747 * This function informs libmount that used from [u]mount.type helper.
2749 * The function also calls mnt_context_disable_helpers() to avoid recursive
2750 * mount.type helpers calling. It you really want to call another
2751 * mount.type helper from your helper, then you have to explicitly enable this
2754 * mnt_context_disable_helpers(cxt, FALSE);
2756 * Returns: 0 on success, negative number in case of error.
2758 int mnt_context_init_helper(struct libmnt_context
*cxt
, int action
,
2759 int flags
__attribute__((__unused__
)))
2766 rc
= mnt_context_disable_helpers(cxt
, TRUE
);
2768 rc
= set_flag(cxt
, MNT_FL_HELPER
, 1);
2770 cxt
->action
= action
;
2772 DBG(CXT
, ul_debugobj(cxt
, "initialized for [u]mount.<type> helper [rc=%d]", rc
));
2777 * mnt_context_helper_setopt:
2779 * @c: getopt() result
2780 * @arg: getopt() optarg
2782 * This function applies the [u]mount.type command line option (for example parsed
2783 * by getopt or getopt_long) to @cxt. All unknown options are ignored and
2784 * then 1 is returned.
2786 * Returns: negative number on error, 1 if @c is unknown option, 0 on success.
2788 int mnt_context_helper_setopt(struct libmnt_context
*cxt
, int c
, char *arg
)
2791 switch(cxt
->action
) {
2793 return mnt_context_mount_setopt(cxt
, c
, arg
);
2794 case MNT_ACT_UMOUNT
:
2795 return mnt_context_umount_setopt(cxt
, c
, arg
);
2802 * mnt_context_is_fs_mounted:
2805 * @mounted: returns 1 for mounted and 0 for non-mounted filesystems
2807 * Please, read the mnt_table_is_fs_mounted() description!
2809 * Returns: 0 on success and negative number in case of error.
2811 int mnt_context_is_fs_mounted(struct libmnt_context
*cxt
,
2812 struct libmnt_fs
*fs
, int *mounted
)
2814 struct libmnt_table
*mountinfo
, *orig
;
2816 struct libmnt_ns
*ns_old
;
2818 if (!cxt
|| !fs
|| !mounted
)
2821 ns_old
= mnt_context_switch_target_ns(cxt
);
2823 return -MNT_ERR_NAMESPACE
;
2825 orig
= cxt
->mountinfo
;
2826 rc
= mnt_context_get_mountinfo(cxt
, &mountinfo
);
2827 if (rc
== -ENOENT
&& mnt_fs_streq_target(fs
, "/proc")) {
2829 mnt_unref_table(cxt
->mountinfo
);
2830 cxt
->mountinfo
= NULL
;
2833 rc
= 0; /* /proc not mounted */
2835 } else if (rc
== 0) {
2836 *mounted
= __mnt_table_is_fs_mounted(mountinfo
, fs
,
2837 mnt_context_get_target_prefix(cxt
));
2841 if (!mnt_context_switch_ns(cxt
, ns_old
))
2842 return -MNT_ERR_NAMESPACE
;
2846 static int mnt_context_add_child(struct libmnt_context
*cxt
, pid_t pid
)
2853 pids
= reallocarray(cxt
->children
, cxt
->nchildren
+ 1, sizeof(pid_t
));
2857 DBG(CXT
, ul_debugobj(cxt
, "add new child %d", pid
));
2858 cxt
->children
= pids
;
2859 cxt
->children
[cxt
->nchildren
++] = pid
;
2864 int mnt_fork_context(struct libmnt_context
*cxt
)
2870 if (!mnt_context_is_parent(cxt
))
2873 DBG(CXT
, ul_debugobj(cxt
, "forking context"));
2880 case -1: /* error */
2881 DBG(CXT
, ul_debugobj(cxt
, "fork failed %m"));
2885 cxt
->pid
= getpid();
2886 mnt_context_enable_fork(cxt
, FALSE
);
2887 DBG(CXT
, ul_debugobj(cxt
, "child created"));
2891 rc
= mnt_context_add_child(cxt
, pid
);
2898 int mnt_context_wait_for_children(struct libmnt_context
*cxt
,
2899 int *nchildren
, int *nerrs
)
2906 assert(mnt_context_is_parent(cxt
));
2908 for (i
= 0; i
< cxt
->nchildren
; i
++) {
2909 pid_t pid
= cxt
->children
[i
];
2910 int rc
= 0, ret
= 0;
2915 DBG(CXT
, ul_debugobj(cxt
,
2916 "waiting for child (%d/%d): %d",
2917 i
+ 1, cxt
->nchildren
, pid
));
2919 rc
= waitpid(pid
, &ret
, 0);
2921 } while (rc
== -1 && errno
== EINTR
);
2926 if (rc
!= -1 && nerrs
) {
2928 (*nerrs
) += WEXITSTATUS(ret
) == 0 ? 0 : 1;
2932 cxt
->children
[i
] = 0;
2936 free(cxt
->children
);
2937 cxt
->children
= NULL
;
2941 static void close_ns(struct libmnt_ns
*ns
)
2949 mnt_unref_cache(ns
->cache
);
2954 * mnt_context_set_target_ns:
2955 * @cxt: mount context
2956 * @path: path to target namespace or NULL
2958 * Sets target namespace to namespace represented by @path. If @path is NULL,
2959 * target namespace is cleared.
2961 * This function sets errno to ENOSYS and returns error if libmount is
2962 * compiled without namespaces support.
2964 * Returns: 0 on success, negative number in case of error.
2968 int mnt_context_set_target_ns(struct libmnt_context
*cxt
, const char *path
)
2973 DBG(CXT
, ul_debugobj(cxt
, "Setting %s as target namespace", path
));
2977 close_ns(&cxt
->ns_orig
);
2978 close_ns(&cxt
->ns_tgt
);
2982 #ifdef USE_LIBMOUNT_SUPPORT_NAMESPACES
2988 /* open original namespace */
2989 if (cxt
->ns_orig
.fd
== -1) {
2990 cxt
->ns_orig
.fd
= open("/proc/self/ns/mnt", O_RDONLY
| O_CLOEXEC
);
2991 if (cxt
->ns_orig
.fd
== -1)
2993 cxt
->ns_orig
.cache
= NULL
;
2996 /* open target (wanted) namespace */
2997 tmp
= open(path
, O_RDONLY
| O_CLOEXEC
);
3001 /* test whether namespace switching works */
3002 DBG(CXT
, ul_debugobj(cxt
, "Trying whether namespace is valid"));
3003 if (setns(tmp
, CLONE_NEWNS
)
3004 || setns(cxt
->ns_orig
.fd
, CLONE_NEWNS
)) {
3006 DBG(CXT
, ul_debugobj(cxt
, "setns(2) failed [errno=%d %m]", errno
));
3010 close_ns(&cxt
->ns_tgt
);
3012 cxt
->ns_tgt
.fd
= tmp
;
3013 cxt
->ns_tgt
.cache
= NULL
;
3020 #else /* ! USE_LIBMOUNT_SUPPORT_NAMESPACES */
3027 * mnt_context_get_target_ns:
3028 * @cxt: mount context
3030 * Returns: pointer to target namespace
3034 struct libmnt_ns
*mnt_context_get_target_ns(struct libmnt_context
*cxt
)
3036 return &cxt
->ns_tgt
;
3040 * mnt_context_get_origin_ns:
3041 * @cxt: mount context
3043 * Returns: pointer to original namespace
3047 struct libmnt_ns
*mnt_context_get_origin_ns(struct libmnt_context
*cxt
)
3049 return &cxt
->ns_orig
;
3054 * mnt_context_switch_ns:
3055 * @cxt: mount context
3056 * @ns: namespace to switch to
3058 * Switch to namespace specified by ns
3063 * struct libmnt_ns *ns_old;
3064 * ns_old = mnt_context_switch_ns(cxt, mnt_context_get_target_ns(cxt));
3066 * mnt_context_switch_ns(cxt, ns_old);
3068 * </informalexample>
3070 * Returns: pointer to previous namespace or NULL on error
3074 struct libmnt_ns
*mnt_context_switch_ns(struct libmnt_context
*cxt
, struct libmnt_ns
*ns
)
3076 struct libmnt_ns
*old
= NULL
;
3082 * If mnt_context_set_target_ns() has never been used than @ns file
3083 * descriptor is -1 and this function is noop.
3086 if (ns
== old
|| ns
->fd
== -1)
3089 #ifdef USE_LIBMOUNT_SUPPORT_NAMESPACES
3090 /* remember the current cache */
3091 if (old
->cache
!= cxt
->cache
) {
3092 mnt_unref_cache(old
->cache
);
3093 old
->cache
= cxt
->cache
;
3094 mnt_ref_cache(old
->cache
);
3098 DBG(CXT
, ul_debugobj(cxt
, "Switching to %s namespace",
3099 ns
== mnt_context_get_target_ns(cxt
) ? "target" :
3100 ns
== mnt_context_get_origin_ns(cxt
) ? "original" : "other"));
3102 if (setns(ns
->fd
, CLONE_NEWNS
)) {
3105 DBG(CXT
, ul_debugobj(cxt
, "setns(2) failed [errno=%d %m]", errno
));
3110 /* update pointer to the current namespace */
3113 /* update pointer to the cache */
3114 mnt_unref_cache(cxt
->cache
);
3115 cxt
->cache
= ns
->cache
;
3116 mnt_ref_cache(cxt
->cache
);
3117 #endif /* USE_LIBMOUNT_SUPPORT_NAMESPACES */
3123 * mnt_context_switch_origin_ns:
3124 * @cxt: mount context
3126 * Switch to original namespace
3128 * This is shorthand for
3131 * mnt_context_switch_ns(cxt, mnt_context_get_origin_ns(cxt));
3133 * </informalexample>
3135 * Returns: pointer to previous namespace or NULL on error
3139 struct libmnt_ns
*mnt_context_switch_origin_ns(struct libmnt_context
*cxt
)
3141 return mnt_context_switch_ns(cxt
, mnt_context_get_origin_ns(cxt
));
3145 * mnt_context_switch_target_ns:
3146 * @cxt: mount context
3148 * Switch to target namespace
3150 * This is shorthand for
3153 * mnt_context_switch_ns(cxt, mnt_context_get_target_ns(cxt));
3155 * </informalexample>
3157 * Returns: pointer to previous namespace or NULL on error
3161 struct libmnt_ns
*mnt_context_switch_target_ns(struct libmnt_context
*cxt
)
3163 return mnt_context_switch_ns(cxt
, mnt_context_get_target_ns(cxt
));
3169 static int test_search_helper(struct libmnt_test
*ts
__attribute__((unused
)),
3170 int argc
, char *argv
[])
3172 struct libmnt_context
*cxt
;
3179 cxt
= mnt_new_context();
3185 mnt_context_get_fs(cxt
); /* just to fill cxt->fs */
3186 cxt
->flags
|= MNT_FL_MOUNTFLAGS_MERGED
; /* fake */
3188 rc
= mnt_context_prepare_helper(cxt
, "mount", type
);
3189 printf("helper is: %s\n", cxt
->helper
? cxt
->helper
: "not found");
3191 mnt_free_context(cxt
);
3196 static struct libmnt_lock
*lock
;
3198 static void lock_fallback(void)
3201 mnt_unlock_file(lock
);
3204 static int test_mount(struct libmnt_test
*ts
__attribute__((unused
)),
3205 int argc
, char *argv
[])
3207 int idx
= 1, rc
= 0;
3208 struct libmnt_context
*cxt
;
3213 cxt
= mnt_new_context();
3217 if (!strcmp(argv
[idx
], "-o")) {
3218 mnt_context_set_options(cxt
, argv
[idx
+ 1]);
3221 if (!strcmp(argv
[idx
], "-t")) {
3222 /* TODO: use mnt_context_set_fstype_pattern() */
3223 mnt_context_set_fstype(cxt
, argv
[idx
+ 1]);
3227 if (argc
== idx
+ 1)
3228 /* mount <mountpoint>|<device> */
3229 mnt_context_set_target(cxt
, argv
[idx
++]);
3231 else if (argc
== idx
+ 2) {
3232 /* mount <device> <mountpoint> */
3233 mnt_context_set_source(cxt
, argv
[idx
++]);
3234 mnt_context_set_target(cxt
, argv
[idx
++]);
3237 /* this is unnecessary! -- libmount is able to internally
3238 * create and manage the lock
3240 lock
= mnt_context_get_lock(cxt
);
3242 atexit(lock_fallback
);
3244 rc
= mnt_context_mount(cxt
);
3246 warn("failed to mount");
3248 printf("successfully mounted\n");
3250 lock
= NULL
; /* because we use atexit lock_fallback */
3251 mnt_free_context(cxt
);
3255 static int test_umount(struct libmnt_test
*ts
__attribute__((unused
)),
3256 int argc
, char *argv
[])
3258 int idx
= 1, rc
= 0;
3259 struct libmnt_context
*cxt
;
3264 cxt
= mnt_new_context();
3268 if (!strcmp(argv
[idx
], "-t")) {
3269 mnt_context_set_fstype(cxt
, argv
[idx
+ 1]);
3273 if (!strcmp(argv
[idx
], "-f")) {
3274 mnt_context_enable_force(cxt
, TRUE
);
3278 if (!strcmp(argv
[idx
], "-l")) {
3279 mnt_context_enable_lazy(cxt
, TRUE
);
3283 if (!strcmp(argv
[idx
], "-r")) {
3284 mnt_context_enable_rdonly_umount(cxt
, TRUE
);
3288 if (argc
== idx
+ 1) {
3289 /* mount <mountpoint>|<device> */
3290 mnt_context_set_target(cxt
, argv
[idx
++]);
3296 lock
= mnt_context_get_lock(cxt
);
3298 atexit(lock_fallback
);
3300 rc
= mnt_context_umount(cxt
);
3302 printf("failed to umount\n");
3304 printf("successfully umounted\n");
3306 lock
= NULL
; /* because we use atexit lock_fallback */
3307 mnt_free_context(cxt
);
3311 static int test_flags(struct libmnt_test
*ts
__attribute__((unused
)),
3312 int argc
, char *argv
[])
3314 int idx
= 1, rc
= 0;
3315 struct libmnt_context
*cxt
;
3316 const char *opt
= NULL
;
3317 unsigned long flags
= 0;
3322 cxt
= mnt_new_context();
3326 if (!strcmp(argv
[idx
], "-o")) {
3327 mnt_context_set_options(cxt
, argv
[idx
+ 1]);
3331 if (argc
== idx
+ 1)
3332 /* mount <mountpoint>|<device> */
3333 mnt_context_set_target(cxt
, argv
[idx
++]);
3335 rc
= mnt_context_prepare_mount(cxt
);
3337 printf("failed to prepare mount %s\n", strerror(-rc
));
3339 opt
= mnt_fs_get_options(cxt
->fs
);
3341 fprintf(stdout
, "options: %s\n", opt
);
3343 mnt_context_get_mflags(cxt
, &flags
);
3344 fprintf(stdout
, "flags: %08lx\n", flags
);
3346 mnt_free_context(cxt
);
3350 static int test_cxtsync(struct libmnt_test
*ts
__attribute__((unused
)),
3351 int argc
, char *argv
[])
3353 struct libmnt_context
*cxt
;
3354 struct libmnt_fs
*fs
;
3355 unsigned long flags
= 0;
3365 rc
= mnt_fs_set_options(fs
, argv
[1]);
3369 cxt
= mnt_new_context();
3373 rc
= mnt_context_set_fs(cxt
, fs
);
3377 rc
= mnt_context_append_options(cxt
, argv
[2]);
3381 rc
= mnt_fs_append_options(fs
, argv
[3]);
3385 mnt_context_get_mflags(cxt
, &flags
);
3387 printf(" fs options: %s\n", mnt_fs_get_options(fs
));
3388 printf("context options: %s\n", mnt_context_get_options(cxt
));
3389 printf(" context mflags: %08lx\n", flags
);
3391 mnt_free_context(cxt
);
3395 static int test_mountall(struct libmnt_test
*ts
__attribute__((unused
)),
3396 int argc
, char *argv
[])
3398 struct libmnt_context
*cxt
;
3399 struct libmnt_iter
*itr
;
3400 struct libmnt_fs
*fs
;
3401 int mntrc
, ignored
, idx
= 1;
3403 cxt
= mnt_new_context();
3404 itr
= mnt_new_iter(MNT_ITER_FORWARD
);
3410 if (argv
[idx
] && !strcmp(argv
[idx
], "-O")) {
3411 mnt_context_set_options_pattern(cxt
, argv
[idx
+ 1]);
3414 if (argv
[idx
] && !strcmp(argv
[idx
], "-t"))
3415 mnt_context_set_fstype_pattern(cxt
, argv
[idx
+ 1]);
3418 while (mnt_context_next_mount(cxt
, itr
, &fs
, &mntrc
, &ignored
) == 0) {
3420 const char *tgt
= mnt_fs_get_target(fs
);
3423 printf("%s: ignored: not match\n", tgt
);
3424 else if (ignored
== 2)
3425 printf("%s: ignored: already mounted\n", tgt
);
3427 else if (!mnt_context_get_status(cxt
)) {
3430 warn("%s: mount failed", tgt
);
3432 warnx("%s: mount failed", tgt
);
3434 printf("%s: successfully mounted\n", tgt
);
3437 mnt_free_context(cxt
);
3443 int main(int argc
, char *argv
[])
3445 struct libmnt_test tss
[] = {
3446 { "--mount", test_mount
, "[-o <opts>] [-t <type>] <spec>|<src> <target>" },
3447 { "--umount", test_umount
, "[-t <type>] [-f][-l][-r] <src>|<target>" },
3448 { "--mount-all", test_mountall
, "[-O <pattern>] [-t <pattern] mount all filesystems from fstab" },
3449 { "--flags", test_flags
, "[-o <opts>] <spec>" },
3450 { "--cxtsync", test_cxtsync
, "<fsopts> <cxtopts> <fsopts>" },
3451 { "--search-helper", test_search_helper
, "<fstype>" },
3454 umask(S_IWGRP
|S_IWOTH
); /* to be compatible with mount(8) */
3456 return mnt_run_test(tss
, argc
, argv
);
3459 #endif /* TEST_PROGRAM */