]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - libmount/src/context.c
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
40 #include "fileutils.h"
42 #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
));
60 INIT_LIST_HEAD(&cxt
->addmounts
);
65 mnt_context_reset_status(cxt
);
71 cxt
->ns_cur
= &cxt
->ns_orig
;
73 /* if we're really root and aren't running setuid */
74 cxt
->restricted
= (uid_t
) 0 == ruid
&& ruid
== euid
? 0 : 1;
76 DBG(CXT
, ul_debugobj(cxt
, "----> allocate %s",
77 cxt
->restricted
? "[RESTRICTED]" : ""));
87 * Deallocates context struct.
89 void mnt_free_context(struct libmnt_context
*cxt
)
94 mnt_reset_context(cxt
);
96 free(cxt
->fstype_pattern
);
97 free(cxt
->optstr_pattern
);
98 free(cxt
->tgt_prefix
);
100 mnt_unref_table(cxt
->fstab
);
101 mnt_unref_cache(cxt
->cache
);
102 mnt_unref_fs(cxt
->fs
);
103 mnt_unref_fs(cxt
->fs_template
);
105 mnt_context_clear_loopdev(cxt
);
106 mnt_free_lock(cxt
->lock
);
107 mnt_free_update(cxt
->update
);
109 mnt_context_set_target_ns(cxt
, NULL
);
113 DBG(CXT
, ul_debugobj(cxt
, "<---- free"));
119 * @cxt: mount context
121 * Resets all information in the context that is directly related to
122 * the latest mount (spec, source, target, mount options, ...).
124 * The match patterns, target namespace, prefix, cached fstab, cached canonicalized
125 * paths and tags and [e]uid are not reset. You have to use
127 * mnt_context_set_fstab(cxt, NULL);
128 * mnt_context_set_cache(cxt, NULL);
129 * mnt_context_set_fstype_pattern(cxt, NULL);
130 * mnt_context_set_options_pattern(cxt, NULL);
131 * mnt_context_set_target_ns(cxt, NULL);
134 * to reset this stuff.
136 * Returns: 0 on success, negative number in case of error.
138 int mnt_reset_context(struct libmnt_context
*cxt
)
145 DBG(CXT
, ul_debugobj(cxt
, "<---- reset [status=%d] ---->",
146 mnt_context_get_status(cxt
)));
150 mnt_unref_fs(cxt
->fs
);
151 mnt_unref_table(cxt
->mtab
);
152 mnt_unref_table(cxt
->utab
);
155 free(cxt
->orig_user
);
161 cxt
->orig_user
= NULL
;
163 cxt
->user_mountflags
= 0;
164 cxt
->mountdata
= NULL
;
165 cxt
->flags
= MNT_FL_DEFAULT
;
167 /* free additional mounts list */
168 while (!list_empty(&cxt
->addmounts
)) {
169 struct libmnt_addmount
*ad
= list_entry(cxt
->addmounts
.next
,
170 struct libmnt_addmount
,
172 mnt_free_addmount(ad
);
175 mnt_context_reset_status(cxt
);
177 if (cxt
->table_fltrcb
)
178 mnt_context_set_tabfilter(cxt
, NULL
, NULL
);
180 /* restore non-resettable flags */
181 cxt
->flags
|= (fl
& MNT_FL_NOMTAB
);
182 cxt
->flags
|= (fl
& MNT_FL_FAKE
);
183 cxt
->flags
|= (fl
& MNT_FL_SLOPPY
);
184 cxt
->flags
|= (fl
& MNT_FL_VERBOSE
);
185 cxt
->flags
|= (fl
& MNT_FL_NOHELPERS
);
186 cxt
->flags
|= (fl
& MNT_FL_LOOPDEL
);
187 cxt
->flags
|= (fl
& MNT_FL_LAZY
);
188 cxt
->flags
|= (fl
& MNT_FL_FORK
);
189 cxt
->flags
|= (fl
& MNT_FL_FORCE
);
190 cxt
->flags
|= (fl
& MNT_FL_NOCANONICALIZE
);
191 cxt
->flags
|= (fl
& MNT_FL_RDONLY_UMOUNT
);
192 cxt
->flags
|= (fl
& MNT_FL_RWONLY_MOUNT
);
193 cxt
->flags
|= (fl
& MNT_FL_NOSWAPMATCH
);
194 cxt
->flags
|= (fl
& MNT_FL_TABPATHS_CHECKED
);
196 mnt_context_apply_template(cxt
);
202 * Saves the current context FS setting (mount options, etc) to make it usable after
203 * mnt_reset_context() or by mnt_context_apply_template(). This is usable for
204 * example for mnt_context_next_mount() where for the next mount operation we
205 * need to restore to the original context setting.
207 * Returns: 0 on success, negative number in case of error.
209 int mnt_context_save_template(struct libmnt_context
*cxt
)
211 struct libmnt_fs
*fs
= NULL
;
216 DBG(CXT
, ul_debugobj(cxt
, "save FS as template"));
219 fs
= mnt_copy_fs(NULL
, cxt
->fs
);
224 mnt_unref_fs(cxt
->fs_template
);
225 cxt
->fs_template
= fs
;
231 * Restores context FS setting from previously saved template (see
232 * mnt_context_save_template()).
234 * Returns: 0 on success, negative number in case of error.
236 int mnt_context_apply_template(struct libmnt_context
*cxt
)
238 struct libmnt_fs
*fs
= NULL
;
244 if (cxt
->fs_template
) {
245 DBG(CXT
, ul_debugobj(cxt
, "copy FS from template"));
246 fs
= mnt_copy_fs(NULL
, cxt
->fs_template
);
249 rc
= mnt_context_set_fs(cxt
, fs
);
252 DBG(CXT
, ul_debugobj(cxt
, "no FS template, reset only"));
253 mnt_unref_fs(cxt
->fs
);
260 int mnt_context_has_template(struct libmnt_context
*cxt
)
262 return cxt
&& cxt
->fs_template
? 1 : 0;
265 struct libmnt_context
*mnt_copy_context(struct libmnt_context
*o
)
267 struct libmnt_context
*n
;
269 n
= mnt_new_context();
273 DBG(CXT
, ul_debugobj(n
, "<---- clone ---->"));
278 n
->fs
= mnt_copy_fs(NULL
, o
->fs
);
284 mnt_ref_table(n
->mtab
);
287 mnt_ref_table(n
->utab
);
289 if (strdup_between_structs(n
, o
, tgt_prefix
))
291 if (strdup_between_structs(n
, o
, helper
))
293 if (strdup_between_structs(n
, o
, orig_user
))
296 n
->mountflags
= o
->mountflags
;
297 n
->mountdata
= o
->mountdata
;
299 mnt_context_reset_status(n
);
301 n
->table_fltrcb
= o
->table_fltrcb
;
302 n
->table_fltrcb_data
= o
->table_fltrcb_data
;
311 * mnt_context_reset_status:
314 * Resets mount(2) and mount.type statuses, so mnt_context_do_mount() or
315 * mnt_context_do_umount() could be again called with the same settings.
317 * BE CAREFUL -- after this soft reset the libmount will NOT parse mount
318 * options, evaluate permissions or apply stuff from fstab.
320 * Returns: 0 on success, negative number in case of error.
322 int mnt_context_reset_status(struct libmnt_context
*cxt
)
327 cxt
->syscall_status
= 1; /* means not called yet */
328 cxt
->helper_exec_status
= 1;
329 cxt
->helper_status
= 0;
333 static int context_init_paths(struct libmnt_context
*cxt
, int writable
)
335 struct libmnt_ns
*ns_old
;
339 #ifdef USE_LIBMOUNT_SUPPORT_MTAB
340 if (!cxt
->mtab_path
) {
341 cxt
->mtab_path
= mnt_get_mtab_path();
342 DBG(CXT
, ul_debugobj(cxt
, "mtab path initialized to: %s", cxt
->mtab_path
));
345 if (!cxt
->utab_path
) {
346 cxt
->utab_path
= mnt_get_utab_path();
347 DBG(CXT
, ul_debugobj(cxt
, "utab path initialized to: %s", cxt
->utab_path
));
351 return 0; /* only paths wanted */
352 if (mnt_context_is_nomtab(cxt
))
353 return 0; /* write mode overridden by mount -n */
354 if (cxt
->flags
& MNT_FL_TABPATHS_CHECKED
)
357 DBG(CXT
, ul_debugobj(cxt
, "checking for writable tab files"));
359 cxt
->mtab_writable
= 0;
361 ns_old
= mnt_context_switch_target_ns(cxt
);
363 return -MNT_ERR_NAMESPACE
;
365 #ifdef USE_LIBMOUNT_SUPPORT_MTAB
366 mnt_has_regular_mtab(&cxt
->mtab_path
, &cxt
->mtab_writable
);
367 if (!cxt
->mtab_writable
)
369 /* use /run/mount/utab if /etc/mtab is useless */
370 mnt_has_regular_utab(&cxt
->utab_path
, &cxt
->utab_writable
);
372 if (!mnt_context_switch_ns(cxt
, ns_old
))
373 return -MNT_ERR_NAMESPACE
;
375 cxt
->flags
|= MNT_FL_TABPATHS_CHECKED
;
379 int mnt_context_mtab_writable(struct libmnt_context
*cxt
)
383 context_init_paths(cxt
, 1);
384 return cxt
->mtab_writable
== 1;
387 int mnt_context_utab_writable(struct libmnt_context
*cxt
)
391 context_init_paths(cxt
, 1);
392 return cxt
->utab_writable
== 1;
395 const char *mnt_context_get_writable_tabpath(struct libmnt_context
*cxt
)
399 context_init_paths(cxt
, 1);
400 return cxt
->mtab_writable
? cxt
->mtab_path
: cxt
->utab_path
;
404 static int set_flag(struct libmnt_context
*cxt
, int flag
, int enable
)
409 DBG(CXT
, ul_debugobj(cxt
, "enabling flag %04x", flag
));
412 DBG(CXT
, ul_debugobj(cxt
, "disabling flag %04x", flag
));
419 * mnt_context_is_restricted:
420 * @cxt: mount context
422 * Returns: 0 for an unrestricted mount (user is root), or 1 for non-root mounts
424 int mnt_context_is_restricted(struct libmnt_context
*cxt
)
426 return cxt
->restricted
;
430 * mnt_context_force_unrestricted:
431 * @cxt: mount context
433 * This function is DANGEROURS as it disables all security policies in libmount.
434 * Don't use if not sure. It removes "restricted" flag from the context, so
435 * libmount will use the current context as for root user.
437 * This function is designed for case you have no any suid permissions, so you
438 * can depend on kernel.
440 * Returns: 0 on success, negative number in case of error.
444 int mnt_context_force_unrestricted(struct libmnt_context
*cxt
)
446 if (mnt_context_is_restricted(cxt
)) {
447 DBG(CXT
, ul_debugobj(cxt
, "force UNRESTRICTED"));
455 * mnt_context_set_optsmode
456 * @cxt: mount context
457 * @mode: MNT_OMODE_* flags
459 * Controls how to use mount optionssource and target paths from fstab/mtab.
461 * @MNT_OMODE_IGNORE: ignore mtab/fstab options
463 * @MNT_OMODE_APPEND: append mtab/fstab options to existing options
465 * @MNT_OMODE_PREPEND: prepend mtab/fstab options to existing options
467 * @MNT_OMODE_REPLACE: replace existing options with options from mtab/fstab
469 * @MNT_OMODE_FORCE: always read mtab/fstab (although source and target are defined)
471 * @MNT_OMODE_FSTAB: read from fstab
473 * @MNT_OMODE_MTAB: read from mtab if fstab not enabled or failed
475 * @MNT_OMODE_NOTAB: do not read fstab/mtab at all
477 * @MNT_OMODE_AUTO: default mode (MNT_OMODE_PREPEND | MNT_OMODE_FSTAB | MNT_OMODE_MTAB)
479 * @MNT_OMODE_USER: default for non-root users (MNT_OMODE_REPLACE | MNT_OMODE_FORCE | MNT_OMODE_FSTAB)
483 * - MNT_OMODE_USER is always used if mount context is in restricted mode
484 * - MNT_OMODE_AUTO is used if nothing else is defined
485 * - the flags are evaluated in this order: MNT_OMODE_NOTAB, MNT_OMODE_FORCE,
486 * MNT_OMODE_FSTAB, MNT_OMODE_MTAB and then the mount options from fstab/mtab
487 * are set according to MNT_OMODE_{IGNORE,APPEND,PREPAND,REPLACE}
489 * Returns: 0 on success, negative number in case of error.
491 int mnt_context_set_optsmode(struct libmnt_context
*cxt
, int mode
)
495 cxt
->optsmode
= mode
;
500 * mnt_context_get_optsmode
501 * @cxt: mount context
503 * Returns: MNT_OMODE_* mask or zero.
506 int mnt_context_get_optsmode(struct libmnt_context
*cxt
)
508 return cxt
->optsmode
;
512 * mnt_context_disable_canonicalize:
513 * @cxt: mount context
514 * @disable: TRUE or FALSE
516 * Enable/disable paths canonicalization and tags evaluation. The libmount context
517 * canonicalizes paths when searching in fstab and when preparing source and target paths
518 * for mount(2) syscall.
520 * This function has an effect on the private (within context) fstab instance only
521 * (see mnt_context_set_fstab()). If you want to use an external fstab then you
522 * need to manage your private struct libmnt_cache (see mnt_table_set_cache(fstab,
525 * Returns: 0 on success, negative number in case of error.
527 int mnt_context_disable_canonicalize(struct libmnt_context
*cxt
, int disable
)
529 return set_flag(cxt
, MNT_FL_NOCANONICALIZE
, disable
);
533 * mnt_context_is_nocanonicalize:
534 * @cxt: mount context
536 * Returns: 1 if no-canonicalize mode is enabled or 0.
538 int mnt_context_is_nocanonicalize(struct libmnt_context
*cxt
)
540 return cxt
->flags
& MNT_FL_NOCANONICALIZE
? 1 : 0;
544 * mnt_context_enable_lazy:
545 * @cxt: mount context
546 * @enable: TRUE or FALSE
548 * Enable/disable lazy umount (see umount(8) man page, option -l).
550 * Returns: 0 on success, negative number in case of error.
552 int mnt_context_enable_lazy(struct libmnt_context
*cxt
, int enable
)
554 return set_flag(cxt
, MNT_FL_LAZY
, enable
);
558 * mnt_context_is_lazy:
559 * @cxt: mount context
561 * Returns: 1 if lazy umount is enabled or 0
563 int mnt_context_is_lazy(struct libmnt_context
*cxt
)
565 return cxt
->flags
& MNT_FL_LAZY
? 1 : 0;
569 * mnt_context_enable_fork:
570 * @cxt: mount context
571 * @enable: TRUE or FALSE
573 * Enable/disable fork(2) call in mnt_context_next_mount() (see mount(8) man
576 * Returns: 0 on success, negative number in case of error.
578 int mnt_context_enable_fork(struct libmnt_context
*cxt
, int enable
)
580 return set_flag(cxt
, MNT_FL_FORK
, enable
);
584 * mnt_context_is_fork:
585 * @cxt: mount context
587 * Returns: 1 if fork (mount -F) is enabled or 0
589 int mnt_context_is_fork(struct libmnt_context
*cxt
)
591 return cxt
->flags
& MNT_FL_FORK
? 1 : 0;
595 * mnt_context_is_parent:
596 * @cxt: mount context
598 * Return: 1 if mount -F enabled and the current context is parent, or 0
600 int mnt_context_is_parent(struct libmnt_context
*cxt
)
602 return mnt_context_is_fork(cxt
) && cxt
->pid
== 0;
606 * mnt_context_is_child:
607 * @cxt: mount context
609 * Return: 1 f the current context is child, or 0
611 int mnt_context_is_child(struct libmnt_context
*cxt
)
613 /* See mnt_fork_context(), the for fork flag is always disabled
614 * for children to avoid recursive forking.
616 return !mnt_context_is_fork(cxt
) && cxt
->pid
;
620 * mnt_context_enable_rdonly_umount:
621 * @cxt: mount context
622 * @enable: TRUE or FALSE
624 * Enable/disable read-only remount on failed umount(2)
625 * (see umount(8) man page, option -r).
627 * Returns: 0 on success, negative number in case of error.
629 int mnt_context_enable_rdonly_umount(struct libmnt_context
*cxt
, int enable
)
631 return set_flag(cxt
, MNT_FL_RDONLY_UMOUNT
, enable
);
635 * mnt_context_is_rdonly_umount
636 * @cxt: mount context
638 * See also mnt_context_enable_rdonly_umount() and umount(8) man page,
641 * Returns: 1 if read-only remount failed umount(2) is enables or 0
643 int mnt_context_is_rdonly_umount(struct libmnt_context
*cxt
)
645 return cxt
->flags
& MNT_FL_RDONLY_UMOUNT
? 1 : 0;
649 * mnt_context_enable_rwonly_mount:
650 * @cxt: mount context
651 * @enable: TRUE or FALSE
653 * Force read-write mount; if enabled libmount will never try MS_RDONLY
654 * after failed mount(2) EROFS. (See mount(8) man page, option -w).
658 * Returns: 0 on success, negative number in case of error.
660 int mnt_context_enable_rwonly_mount(struct libmnt_context
*cxt
, int enable
)
662 return set_flag(cxt
, MNT_FL_RWONLY_MOUNT
, enable
);
666 * mnt_context_is_rwonly_mount
667 * @cxt: mount context
669 * See also mnt_context_enable_rwonly_mount() and mount(8) man page,
674 * Returns: 1 if only read-write mount is allowed.
676 int mnt_context_is_rwonly_mount(struct libmnt_context
*cxt
)
678 return cxt
->flags
& MNT_FL_RWONLY_MOUNT
? 1 : 0;
682 * mnt_context_forced_rdonly:
683 * @cxt: mount context
685 * See also mnt_context_enable_rwonly_mount().
689 * Returns: 1 if mounted read-only on write-protected device.
691 int mnt_context_forced_rdonly(struct libmnt_context
*cxt
)
693 return cxt
->flags
& MNT_FL_FORCED_RDONLY
? 1 : 0;
697 * mnt_context_disable_helpers:
698 * @cxt: mount context
699 * @disable: TRUE or FALSE
701 * Enable/disable /sbin/[u]mount.* helpers (see mount(8) man page, option -i).
703 * Returns: 0 on success, negative number in case of error.
705 int mnt_context_disable_helpers(struct libmnt_context
*cxt
, int disable
)
707 return set_flag(cxt
, MNT_FL_NOHELPERS
, disable
);
711 * mnt_context_is_nohelpers
712 * @cxt: mount context
714 * Returns: 1 if helpers are disabled (mount -i) or 0
716 int mnt_context_is_nohelpers(struct libmnt_context
*cxt
)
718 return cxt
->flags
& MNT_FL_NOHELPERS
? 1 : 0;
723 * mnt_context_enable_sloppy:
724 * @cxt: mount context
725 * @enable: TRUE or FALSE
727 * Set/unset sloppy mounting (see mount(8) man page, option -s).
729 * Returns: 0 on success, negative number in case of error.
731 int mnt_context_enable_sloppy(struct libmnt_context
*cxt
, int enable
)
733 return set_flag(cxt
, MNT_FL_SLOPPY
, enable
);
737 * mnt_context_is_sloppy:
738 * @cxt: mount context
740 * Returns: 1 if sloppy flag is enabled or 0
742 int mnt_context_is_sloppy(struct libmnt_context
*cxt
)
744 return cxt
->flags
& MNT_FL_SLOPPY
? 1 : 0;
748 * mnt_context_enable_fake:
749 * @cxt: mount context
750 * @enable: TRUE or FALSE
752 * Enable/disable fake mounting (see mount(8) man page, option -f).
754 * Returns: 0 on success, negative number in case of error.
756 int mnt_context_enable_fake(struct libmnt_context
*cxt
, int enable
)
758 return set_flag(cxt
, MNT_FL_FAKE
, enable
);
762 * mnt_context_is_fake:
763 * @cxt: mount context
765 * Returns: 1 if fake flag is enabled or 0
767 int mnt_context_is_fake(struct libmnt_context
*cxt
)
769 return cxt
->flags
& MNT_FL_FAKE
? 1 : 0;
773 * mnt_context_disable_mtab:
774 * @cxt: mount context
775 * @disable: TRUE or FALSE
777 * Disable/enable mtab update (see mount(8) man page, option -n).
779 * Returns: 0 on success, negative number in case of error.
781 int mnt_context_disable_mtab(struct libmnt_context
*cxt
, int disable
)
783 return set_flag(cxt
, MNT_FL_NOMTAB
, disable
);
787 * mnt_context_is_nomtab:
788 * @cxt: mount context
790 * Returns: 1 if no-mtab is enabled or 0
792 int mnt_context_is_nomtab(struct libmnt_context
*cxt
)
794 return cxt
->flags
& MNT_FL_NOMTAB
? 1 : 0;
798 * mnt_context_disable_swapmatch:
799 * @cxt: mount context
800 * @disable: TRUE or FALSE
802 * Disable/enable swap between source and target for mount(8) if only one path
805 * Returns: 0 on success, negative number in case of error.
807 int mnt_context_disable_swapmatch(struct libmnt_context
*cxt
, int disable
)
809 return set_flag(cxt
, MNT_FL_NOSWAPMATCH
, disable
);
813 * mnt_context_is_swapmatch:
814 * @cxt: mount context
816 * Returns: 1 if swap between source and target is allowed (default is 1) or 0.
818 int mnt_context_is_swapmatch(struct libmnt_context
*cxt
)
820 return cxt
->flags
& MNT_FL_NOSWAPMATCH
? 0 : 1;
824 * mnt_context_enable_force:
825 * @cxt: mount context
826 * @enable: TRUE or FALSE
828 * Enable/disable force umounting (see umount(8) man page, option -f).
830 * Returns: 0 on success, negative number in case of error.
832 int mnt_context_enable_force(struct libmnt_context
*cxt
, int enable
)
834 return set_flag(cxt
, MNT_FL_FORCE
, enable
);
838 * mnt_context_is_force
839 * @cxt: mount context
841 * Returns: 1 if force umounting flag is enabled or 0
843 int mnt_context_is_force(struct libmnt_context
*cxt
)
845 return cxt
->flags
& MNT_FL_FORCE
? 1 : 0;
849 * mnt_context_enable_verbose:
850 * @cxt: mount context
851 * @enable: TRUE or FALSE
853 * Enable/disable verbose output (TODO: not implemented yet)
855 * Returns: 0 on success, negative number in case of error.
857 int mnt_context_enable_verbose(struct libmnt_context
*cxt
, int enable
)
859 return set_flag(cxt
, MNT_FL_VERBOSE
, enable
);
863 * mnt_context_is_verbose
864 * @cxt: mount context
866 * Returns: 1 if verbose flag is enabled or 0
868 int mnt_context_is_verbose(struct libmnt_context
*cxt
)
870 return cxt
->flags
& MNT_FL_VERBOSE
? 1 : 0;
874 * mnt_context_enable_loopdel:
875 * @cxt: mount context
876 * @enable: TRUE or FALSE
878 * Enable/disable the loop delete (destroy) after umount (see umount(8), option -d)
880 * Returns: 0 on success, negative number in case of error.
882 int mnt_context_enable_loopdel(struct libmnt_context
*cxt
, int enable
)
884 return set_flag(cxt
, MNT_FL_LOOPDEL
, enable
);
888 * mnt_context_is_loopdel:
889 * @cxt: mount context
891 * Returns: 1 if loop device should be deleted after umount (umount -d) or 0.
893 int mnt_context_is_loopdel(struct libmnt_context
*cxt
)
895 return cxt
->flags
& MNT_FL_LOOPDEL
? 1 : 0;
899 * mnt_context_set_fs:
900 * @cxt: mount context
901 * @fs: filesystem description
903 * The mount context uses private @fs by default. This function allows to
904 * overwrite the private @fs with an external instance. This function
905 * increments @fs reference counter (and decrement reference counter of the
908 * The @fs will be modified by mnt_context_set_{source,target,options,fstype}
909 * functions, If the @fs is NULL, then all current FS specific settings (source,
910 * target, etc., exclude spec) are reset.
912 * Returns: 0 on success, negative number in case of error.
914 int mnt_context_set_fs(struct libmnt_context
*cxt
, struct libmnt_fs
*fs
)
919 DBG(CXT
, ul_debugobj(cxt
, "setting new FS"));
920 mnt_ref_fs(fs
); /* new */
921 mnt_unref_fs(cxt
->fs
); /* old */
927 * mnt_context_get_fs:
928 * @cxt: mount context
930 * The FS contains the basic description of mountpoint, fs type and so on.
931 * Note that the FS is modified by mnt_context_set_{source,target,options,fstype}
934 * Returns: pointer to FS description or NULL in case of a calloc() error.
936 struct libmnt_fs
*mnt_context_get_fs(struct libmnt_context
*cxt
)
941 cxt
->fs
= mnt_new_fs();
946 * mnt_context_get_fs_userdata:
947 * @cxt: mount context
949 * Returns: pointer to userdata or NULL.
951 void *mnt_context_get_fs_userdata(struct libmnt_context
*cxt
)
953 return cxt
->fs
? mnt_fs_get_userdata(cxt
->fs
) : NULL
;
957 * mnt_context_get_fstab_userdata:
958 * @cxt: mount context
960 * Returns: pointer to userdata or NULL.
962 void *mnt_context_get_fstab_userdata(struct libmnt_context
*cxt
)
964 return cxt
->fstab
? mnt_table_get_userdata(cxt
->fstab
) : NULL
;
968 * mnt_context_get_mtab_userdata:
969 * @cxt: mount context
971 * Returns: pointer to userdata or NULL.
973 void *mnt_context_get_mtab_userdata(struct libmnt_context
*cxt
)
975 return cxt
->mtab
? mnt_table_get_userdata(cxt
->mtab
) : NULL
;
979 * mnt_context_set_source:
980 * @cxt: mount context
981 * @source: mount source (device, directory, UUID, LABEL, ...)
983 * Note that libmount does not interpret "nofail" (MNT_MS_NOFAIL)
984 * mount option. The real return code is always returned, when
985 * the device does not exist then it's usually MNT_ERR_NOSOURCE
986 * from libmount or ENOENT, ENOTDIR, ENOTBLK, ENXIO from mount(2).
988 * Returns: 0 on success, negative number in case of error.
990 int mnt_context_set_source(struct libmnt_context
*cxt
, const char *source
)
992 return mnt_fs_set_source(mnt_context_get_fs(cxt
), source
);
996 * mnt_context_get_source:
997 * @cxt: mount context
999 * Returns: returns pointer or NULL in case of error or if not set.
1001 const char *mnt_context_get_source(struct libmnt_context
*cxt
)
1003 return mnt_fs_get_source(mnt_context_get_fs(cxt
));
1007 * mnt_context_set_target:
1008 * @cxt: mount context
1009 * @target: mountpoint
1011 * Returns: 0 on success, negative number in case of error.
1013 int mnt_context_set_target(struct libmnt_context
*cxt
, const char *target
)
1015 return mnt_fs_set_target(mnt_context_get_fs(cxt
), target
);
1019 * mnt_context_get_target:
1020 * @cxt: mount context
1022 * Returns: returns pointer or NULL in case of error or if not set.
1024 const char *mnt_context_get_target(struct libmnt_context
*cxt
)
1026 return mnt_fs_get_target(mnt_context_get_fs(cxt
));
1030 * mnt_context_set_target_prefix:
1031 * @cxt: mount context
1032 * @path: mountpoint prefix
1034 * Returns: 0 on success, negative number in case of error.
1036 int mnt_context_set_target_prefix(struct libmnt_context
*cxt
, const char *path
)
1047 free(cxt
->tgt_prefix
);
1048 cxt
->tgt_prefix
= p
;
1054 * mnt_context_get_target_prefix:
1055 * @cxt: mount context
1057 * Returns: returns pointer or NULL in case of error or if not set.
1059 const char *mnt_context_get_target_prefix(struct libmnt_context
*cxt
)
1061 return cxt
? cxt
->tgt_prefix
: NULL
;
1066 * mnt_context_set_fstype:
1067 * @cxt: mount context
1068 * @fstype: filesystem type
1070 * Note that the @fstype has to be a FS type. For patterns with
1071 * comma-separated list of filesystems or for the "nofs" notation, use
1072 * mnt_context_set_fstype_pattern().
1074 * Returns: 0 on success, negative number in case of error.
1076 int mnt_context_set_fstype(struct libmnt_context
*cxt
, const char *fstype
)
1078 return mnt_fs_set_fstype(mnt_context_get_fs(cxt
), fstype
);
1082 * mnt_context_get_fstype:
1083 * @cxt: mount context
1085 * Returns: pointer or NULL in case of error or if not set.
1087 const char *mnt_context_get_fstype(struct libmnt_context
*cxt
)
1089 return mnt_fs_get_fstype(mnt_context_get_fs(cxt
));
1093 * mnt_context_set_options:
1094 * @cxt: mount context
1095 * @optstr: comma delimited mount options
1097 * Note that that MS_MOVE cannot be specified as "string". It's operation that
1098 * is no supported in fstab (etc.)
1100 * Returns: 0 on success, negative number in case of error.
1102 int mnt_context_set_options(struct libmnt_context
*cxt
, const char *optstr
)
1104 return mnt_fs_set_options(mnt_context_get_fs(cxt
), optstr
);
1108 * mnt_context_append_options:
1109 * @cxt: mount context
1110 * @optstr: comma delimited mount options
1112 * Returns: 0 on success, negative number in case of error.
1114 int mnt_context_append_options(struct libmnt_context
*cxt
, const char *optstr
)
1116 return mnt_fs_append_options(mnt_context_get_fs(cxt
), optstr
);
1120 * mnt_context_get_options:
1121 * @cxt: mount context
1123 * This function returns mount options set by mnt_context_set_options() or
1124 * mnt_context_append_options().
1126 * Note that *after* mnt_context_prepare_mount(), the mount options string
1127 * may also include options set by mnt_context_set_mflags() or other options
1128 * generated by this library.
1130 * Returns: pointer or NULL
1132 const char *mnt_context_get_options(struct libmnt_context
*cxt
)
1134 return mnt_fs_get_options(mnt_context_get_fs(cxt
));
1138 * mnt_context_set_fstype_pattern:
1139 * @cxt: mount context
1140 * @pattern: FS name pattern (or NULL to reset the current setting)
1142 * See mount(8), option -t.
1144 * Returns: 0 on success, negative number in case of error.
1146 int mnt_context_set_fstype_pattern(struct libmnt_context
*cxt
, const char *pattern
)
1153 p
= strdup(pattern
);
1157 free(cxt
->fstype_pattern
);
1158 cxt
->fstype_pattern
= p
;
1163 * mnt_context_set_options_pattern:
1164 * @cxt: mount context
1165 * @pattern: options pattern (or NULL to reset the current setting)
1167 * See mount(8), option -O.
1169 * Returns: 0 on success, negative number in case of error.
1171 int mnt_context_set_options_pattern(struct libmnt_context
*cxt
, const char *pattern
)
1178 p
= strdup(pattern
);
1182 free(cxt
->optstr_pattern
);
1183 cxt
->optstr_pattern
= p
;
1188 * mnt_context_set_fstab:
1189 * @cxt: mount context
1192 * The mount context reads /etc/fstab to the private struct libmnt_table by default.
1193 * This function allows to overwrite the private fstab with an external
1196 * This function modify the @tb reference counter. This function does not set
1197 * the cache for the @tb. You have to explicitly call mnt_table_set_cache(tb,
1198 * mnt_context_get_cache(cxt));
1200 * The fstab is used read-only and is not modified, it should be possible to
1201 * share the fstab between more mount contexts (TODO: test it.)
1203 * If the @tb argument is NULL, then the current private fstab instance is
1206 * Returns: 0 on success, negative number in case of error.
1208 int mnt_context_set_fstab(struct libmnt_context
*cxt
, struct libmnt_table
*tb
)
1213 mnt_ref_table(tb
); /* new */
1214 mnt_unref_table(cxt
->fstab
); /* old */
1221 * mnt_context_get_fstab:
1222 * @cxt: mount context
1223 * @tb: returns fstab
1225 * See also mnt_table_parse_fstab() for more details about fstab.
1227 * Returns: 0 on success, negative number in case of error.
1229 int mnt_context_get_fstab(struct libmnt_context
*cxt
, struct libmnt_table
**tb
)
1231 struct libmnt_ns
*ns_old
;
1238 cxt
->fstab
= mnt_new_table();
1241 if (cxt
->table_errcb
)
1242 mnt_table_set_parser_errcb(cxt
->fstab
, cxt
->table_errcb
);
1244 ns_old
= mnt_context_switch_target_ns(cxt
);
1246 return -MNT_ERR_NAMESPACE
;
1248 mnt_table_set_cache(cxt
->fstab
, mnt_context_get_cache(cxt
));
1249 rc
= mnt_table_parse_fstab(cxt
->fstab
, NULL
);
1251 if (!mnt_context_switch_ns(cxt
, ns_old
))
1252 return -MNT_ERR_NAMESPACE
;
1264 * mnt_context_get_mtab:
1265 * @cxt: mount context
1268 * See also mnt_table_parse_mtab() for more details about mtab/mountinfo. The
1269 * result will be deallocated by mnt_free_context(@cxt).
1271 * Returns: 0 on success, negative number in case of error.
1273 int mnt_context_get_mtab(struct libmnt_context
*cxt
, struct libmnt_table
**tb
)
1276 struct libmnt_ns
*ns_old
= NULL
;
1281 ns_old
= mnt_context_switch_target_ns(cxt
);
1283 return -MNT_ERR_NAMESPACE
;
1285 context_init_paths(cxt
, 0);
1287 cxt
->mtab
= mnt_new_table();
1293 if (cxt
->table_errcb
)
1294 mnt_table_set_parser_errcb(cxt
->mtab
, cxt
->table_errcb
);
1295 if (cxt
->table_fltrcb
)
1296 mnt_table_set_parser_fltrcb(cxt
->mtab
,
1298 cxt
->table_fltrcb_data
);
1300 mnt_table_set_cache(cxt
->mtab
, mnt_context_get_cache(cxt
));
1303 * Note that mtab_path is NULL if mtab is useless or unsupported
1306 /* utab already parsed, don't parse it again */
1307 rc
= __mnt_table_parse_mtab(cxt
->mtab
,
1308 cxt
->mtab_path
, cxt
->utab
);
1310 rc
= mnt_table_parse_mtab(cxt
->mtab
, cxt
->mtab_path
);
1318 DBG(CXT
, ul_debugobj(cxt
, "mtab requested [nents=%d]",
1319 mnt_table_get_nents(cxt
->mtab
)));
1322 if (ns_old
&& !mnt_context_switch_ns(cxt
, ns_old
))
1323 return -MNT_ERR_NAMESPACE
;
1329 * Called by mtab parser to filter out entries, non-zero means that
1330 * an entry has to be filtered out.
1332 static int mtab_filter(struct libmnt_fs
*fs
, void *data
)
1336 if (mnt_fs_streq_target(fs
, data
))
1338 if (mnt_fs_streq_srcpath(fs
, data
))
1344 * The same like mnt_context_get_mtab(), but does not read all mountinfo/mtab
1345 * file, but only entries relevant for @tgt.
1347 int mnt_context_get_mtab_for_target(struct libmnt_context
*cxt
,
1348 struct libmnt_table
**mtab
,
1352 struct libmnt_cache
*cache
= NULL
;
1353 char *cn_tgt
= NULL
;
1355 struct libmnt_ns
*ns_old
;
1357 ns_old
= mnt_context_switch_target_ns(cxt
);
1359 return -MNT_ERR_NAMESPACE
;
1361 if (mnt_context_is_nocanonicalize(cxt
))
1362 mnt_context_set_tabfilter(cxt
, mtab_filter
, (void *) tgt
);
1364 else if (mnt_stat_mountpoint(tgt
, &st
) == 0 && S_ISDIR(st
.st_mode
)) {
1365 cache
= mnt_context_get_cache(cxt
);
1366 cn_tgt
= mnt_resolve_path(tgt
, cache
);
1368 mnt_context_set_tabfilter(cxt
, mtab_filter
, cn_tgt
);
1371 rc
= mnt_context_get_mtab(cxt
, mtab
);
1372 mnt_context_set_tabfilter(cxt
, NULL
, NULL
);
1374 if (!mnt_context_switch_ns(cxt
, ns_old
))
1375 return -MNT_ERR_NAMESPACE
;
1377 if (cn_tgt
&& !cache
)
1384 * Allows to specify a filter for tab file entries. The filter is called by
1385 * the table parser. Currently used for mtab and utab only.
1387 int mnt_context_set_tabfilter(struct libmnt_context
*cxt
,
1388 int (*fltr
)(struct libmnt_fs
*, void *),
1394 cxt
->table_fltrcb
= fltr
;
1395 cxt
->table_fltrcb_data
= data
;
1398 mnt_table_set_parser_fltrcb(cxt
->mtab
,
1400 cxt
->table_fltrcb_data
);
1402 DBG(CXT
, ul_debugobj(cxt
, "tabfilter %s", fltr
? "ENABLED!" : "disabled"));
1407 * mnt_context_get_table:
1408 * @cxt: mount context
1409 * @filename: e.g. /proc/self/mountinfo
1410 * @tb: returns the table
1412 * This function allocates a new table and parses the @file. The parser error
1413 * callback and cache for tags and paths is set according to the @cxt setting.
1414 * See also mnt_table_parse_file().
1416 * It's strongly recommended to use the mnt_context_get_mtab() and
1417 * mnt_context_get_fstab() functions for mtab and fstab files. This function
1418 * does not care about LIBMOUNT_* env.variables and does not merge userspace
1421 * The result will NOT be deallocated by mnt_free_context(@cxt).
1423 * Returns: 0 on success, negative number in case of error.
1425 int mnt_context_get_table(struct libmnt_context
*cxt
,
1426 const char *filename
, struct libmnt_table
**tb
)
1429 struct libmnt_ns
*ns_old
;
1434 *tb
= mnt_new_table();
1438 if (cxt
->table_errcb
)
1439 mnt_table_set_parser_errcb(*tb
, cxt
->table_errcb
);
1441 ns_old
= mnt_context_switch_target_ns(cxt
);
1443 return -MNT_ERR_NAMESPACE
;
1445 rc
= mnt_table_parse_file(*tb
, filename
);
1448 mnt_unref_table(*tb
);
1452 mnt_table_set_cache(*tb
, mnt_context_get_cache(cxt
));
1455 if (!mnt_context_switch_ns(cxt
, ns_old
))
1456 return -MNT_ERR_NAMESPACE
;
1462 * mnt_context_set_tables_errcb
1463 * @cxt: mount context
1464 * @cb: pointer to callback function
1466 * The error callback is used for all tab files (e.g. mtab, fstab)
1467 * parsed within the context.
1469 * See also mnt_context_get_mtab(),
1470 * mnt_context_get_fstab(),
1471 * mnt_table_set_parser_errcb().
1473 * Returns: 0 on success, negative number in case of error.
1475 int mnt_context_set_tables_errcb(struct libmnt_context
*cxt
,
1476 int (*cb
)(struct libmnt_table
*tb
, const char *filename
, int line
))
1482 mnt_table_set_parser_errcb(cxt
->mtab
, cb
);
1484 mnt_table_set_parser_errcb(cxt
->fstab
, cb
);
1486 cxt
->table_errcb
= cb
;
1491 * mnt_context_set_cache:
1492 * @cxt: mount context
1493 * @cache: cache instance or NULL
1495 * The mount context maintains a private struct libmnt_cache by default. This
1496 * function allows to overwrite the private cache with an external instance.
1497 * This function increments cache reference counter.
1499 * If the @cache argument is NULL, then the current cache instance is reset.
1500 * This function apply the cache to fstab and mtab instances (if already
1503 * The old cache instance reference counter is de-incremented.
1505 * Returns: 0 on success, negative number in case of error.
1507 int mnt_context_set_cache(struct libmnt_context
*cxt
, struct libmnt_cache
*cache
)
1512 mnt_ref_cache(cache
); /* new */
1513 mnt_unref_cache(cxt
->cache
); /* old */
1518 mnt_table_set_cache(cxt
->mtab
, cache
);
1520 mnt_table_set_cache(cxt
->fstab
, cache
);
1526 * mnt_context_get_cache
1527 * @cxt: mount context
1529 * See also mnt_context_set_cache().
1531 * Returns: pointer to cache or NULL if canonicalization is disabled.
1533 struct libmnt_cache
*mnt_context_get_cache(struct libmnt_context
*cxt
)
1535 if (!cxt
|| mnt_context_is_nocanonicalize(cxt
))
1539 struct libmnt_cache
*cache
= mnt_new_cache();
1540 mnt_context_set_cache(cxt
, cache
);
1541 mnt_unref_cache(cache
);
1547 * mnt_context_set_passwd_cb:
1548 * @cxt: mount context
1549 * @get: callback to get password
1550 * @release: callback to release (deallocate) password
1552 * Sets callbacks for encryption password (e.g encrypted loopdev). This
1553 * function is deprecated (encrypted loops are no longer supported).
1555 * Returns: 0 on success, negative number in case of error.
1557 int mnt_context_set_passwd_cb(struct libmnt_context
*cxt
,
1558 char *(*get
)(struct libmnt_context
*),
1559 void (*release
)(struct libmnt_context
*, char *))
1563 cxt
->pwd_get_cb
= get
;
1564 cxt
->pwd_release_cb
= release
;
1569 * mnt_context_get_lock:
1570 * @cxt: mount context
1572 * The libmount applications don't have to care about mtab locking, but with a
1573 * small exception: the application has to be able to remove the lock file when
1574 * interrupted by signal or signals have to be ignored when the lock is locked.
1576 * The default behavior is to ignore all signals (except SIGALRM and
1577 * SIGTRAP for mtab update) when the lock is locked. If this behavior
1578 * is unacceptable, then use:
1580 * lc = mnt_context_get_lock(cxt);
1582 * mnt_lock_block_signals(lc, FALSE);
1584 * and don't forget to call mnt_unlock_file(lc) before exit.
1586 * Returns: pointer to lock struct or NULL.
1588 struct libmnt_lock
*mnt_context_get_lock(struct libmnt_context
*cxt
)
1591 * DON'T call this function within libmount, it will always allocate
1592 * the lock. The mnt_update_* functions are able to allocate the lock
1593 * only when mtab/utab update is really necessary.
1595 if (!cxt
|| mnt_context_is_nomtab(cxt
))
1599 cxt
->lock
= mnt_new_lock(
1600 mnt_context_get_writable_tabpath(cxt
), 0);
1602 mnt_lock_block_signals(cxt
->lock
, TRUE
);
1608 * mnt_context_set_mflags:
1609 * @cxt: mount context
1610 * @flags: mount(2) flags (MS_* flags)
1612 * Sets mount flags (see mount(2) man page).
1614 * Note that mount context allows to define mount options by mount flags. It
1615 * means you can for example use
1617 * mnt_context_set_mflags(cxt, MS_NOEXEC | MS_NOSUID);
1621 * mnt_context_set_options(cxt, "noexec,nosuid");
1623 * both of these calls have the same effect.
1625 * Be careful if you want to use MS_REC flag -- in this case the bit is applied
1626 * to all bind/slave/etc. options. If you want to mix more propadation flags
1627 * and/or bind operations than it's better to specify mount options by
1630 * Returns: 0 on success, negative number in case of error.
1632 int mnt_context_set_mflags(struct libmnt_context
*cxt
, unsigned long flags
)
1637 cxt
->mountflags
= flags
;
1639 if ((cxt
->flags
& MNT_FL_MOUNTOPTS_FIXED
) && cxt
->fs
)
1641 * the final mount options are already generated, refresh...
1643 return mnt_optstr_apply_flags(
1644 &cxt
->fs
->vfs_optstr
,
1646 mnt_get_builtin_optmap(MNT_LINUX_MAP
));
1652 * mnt_context_get_mflags:
1653 * @cxt: mount context
1654 * @flags: returns MS_* mount flags
1656 * Converts mount options string to MS_* flags and bitwise-OR the result with
1657 * the already defined flags (see mnt_context_set_mflags()).
1659 * Returns: 0 on success, negative number in case of error.
1661 int mnt_context_get_mflags(struct libmnt_context
*cxt
, unsigned long *flags
)
1664 struct list_head
*p
;
1670 if (!(cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
) && cxt
->fs
) {
1671 const char *o
= mnt_fs_get_options(cxt
->fs
);
1673 rc
= mnt_optstr_get_flags(o
, flags
,
1674 mnt_get_builtin_optmap(MNT_LINUX_MAP
));
1677 list_for_each(p
, &cxt
->addmounts
) {
1678 struct libmnt_addmount
*ad
=
1679 list_entry(p
, struct libmnt_addmount
, mounts
);
1681 *flags
|= ad
->mountflags
;
1685 *flags
|= cxt
->mountflags
;
1690 * mnt_context_set_user_mflags:
1691 * @cxt: mount context
1692 * @flags: mount(2) flags (MNT_MS_* flags, e.g. MNT_MS_LOOP)
1694 * Sets userspace mount flags.
1696 * See also notes for mnt_context_set_mflags().
1698 * Returns: 0 on success, negative number in case of error.
1700 int mnt_context_set_user_mflags(struct libmnt_context
*cxt
, unsigned long flags
)
1704 cxt
->user_mountflags
= flags
;
1709 * mnt_context_get_user_mflags:
1710 * @cxt: mount context
1711 * @flags: returns mount flags
1713 * Converts mount options string to MNT_MS_* flags and bitwise-OR the result
1714 * with the already defined flags (see mnt_context_set_user_mflags()).
1716 * Returns: 0 on success, negative number in case of error.
1718 int mnt_context_get_user_mflags(struct libmnt_context
*cxt
, unsigned long *flags
)
1726 if (!(cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
) && cxt
->fs
) {
1727 const char *o
= mnt_fs_get_user_options(cxt
->fs
);
1729 rc
= mnt_optstr_get_flags(o
, flags
,
1730 mnt_get_builtin_optmap(MNT_USERSPACE_MAP
));
1733 *flags
|= cxt
->user_mountflags
;
1738 * mnt_context_set_mountdata:
1739 * @cxt: mount context
1740 * @data: mount(2) data
1742 * The mount context generates mountdata from mount options by default. This
1743 * function allows to overwrite this behavior, and @data will be used instead
1746 * The libmount does not deallocate the data by mnt_free_context(). Note that
1747 * NULL is also valid mount data.
1749 * Returns: 0 on success, negative number in case of error.
1751 int mnt_context_set_mountdata(struct libmnt_context
*cxt
, void *data
)
1755 cxt
->mountdata
= data
;
1756 cxt
->flags
|= MNT_FL_MOUNTDATA
;
1761 * Translates LABEL/UUID/path to mountable path
1763 int mnt_context_prepare_srcpath(struct libmnt_context
*cxt
)
1765 const char *path
= NULL
;
1766 struct libmnt_cache
*cache
;
1767 const char *t
, *v
, *src
;
1769 struct libmnt_ns
*ns_old
;
1773 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
1775 DBG(CXT
, ul_debugobj(cxt
, "preparing source path"));
1777 src
= mnt_fs_get_source(cxt
->fs
);
1779 if (!src
&& mnt_context_propagation_only(cxt
))
1780 /* mount --make-{shared,private,...} */
1781 return mnt_fs_set_source(cxt
->fs
, "none");
1783 /* ignore filesystems without source or filesystems
1784 * where the source is a quasi-path (//foo/bar)
1786 if (!src
|| mnt_fs_is_netfs(cxt
->fs
))
1789 DBG(CXT
, ul_debugobj(cxt
, "srcpath '%s'", src
));
1791 ns_old
= mnt_context_switch_target_ns(cxt
);
1793 return -MNT_ERR_NAMESPACE
;
1795 cache
= mnt_context_get_cache(cxt
);
1797 if (!mnt_fs_get_tag(cxt
->fs
, &t
, &v
)) {
1799 * Source is TAG (evaluate)
1802 path
= mnt_resolve_tag(t
, v
, cache
);
1804 rc
= path
? mnt_fs_set_source(cxt
->fs
, path
) : -MNT_ERR_NOSOURCE
;
1806 } else if (cache
&& !mnt_fs_is_pseudofs(cxt
->fs
)) {
1808 * Source is PATH (canonicalize)
1810 path
= mnt_resolve_path(src
, cache
);
1811 if (path
&& strcmp(path
, src
))
1812 rc
= mnt_fs_set_source(cxt
->fs
, path
);
1816 DBG(CXT
, ul_debugobj(cxt
, "failed to prepare srcpath [rc=%d]", rc
));
1823 if ((cxt
->mountflags
& (MS_BIND
| MS_MOVE
| MS_REMOUNT
))
1824 || mnt_fs_is_pseudofs(cxt
->fs
)) {
1825 DBG(CXT
, ul_debugobj(cxt
, "REMOUNT/BIND/MOVE/pseudo FS source: %s", path
));
1830 * Initialize loop device
1832 if (mnt_context_is_loopdev(cxt
)) {
1833 rc
= mnt_context_setup_loopdev(cxt
);
1838 DBG(CXT
, ul_debugobj(cxt
, "final srcpath '%s'",
1839 mnt_fs_get_source(cxt
->fs
)));
1842 if (!mnt_context_switch_ns(cxt
, ns_old
))
1843 return -MNT_ERR_NAMESPACE
;
1847 /* create a mountpoint if X-mount.mkdir[=<mode>] specified */
1848 static int mkdir_target(const char *tgt
, struct libmnt_fs
*fs
)
1859 if (mnt_optstr_get_option(fs
->user_optstr
, "X-mount.mkdir", &mstr
, &mstr_sz
) != 0 &&
1860 mnt_optstr_get_option(fs
->user_optstr
, "x-mount.mkdir", &mstr
, &mstr_sz
) != 0) /* obsolete */
1863 DBG(CXT
, ul_debug("mkdir %s (%s) wanted", tgt
, mstr
));
1865 if (mnt_stat_mountpoint(tgt
, &st
) == 0)
1868 if (mstr
&& mstr_sz
) {
1872 mode
= strtol(mstr
, &end
, 8);
1874 if (errno
|| !end
|| mstr
+ mstr_sz
!= end
) {
1875 DBG(CXT
, ul_debug("failed to parse mkdir mode '%s'", mstr
));
1876 return -MNT_ERR_MOUNTOPT
;
1881 mode
= S_IRWXU
| /* 0755 */
1885 rc
= mkdir_p(tgt
, mode
);
1887 DBG(CXT
, ul_debug("mkdir %s failed: %m", tgt
));
1892 int mnt_context_prepare_target(struct libmnt_context
*cxt
)
1894 const char *tgt
, *prefix
;
1895 struct libmnt_cache
*cache
;
1897 struct libmnt_ns
*ns_old
;
1901 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
1903 DBG(CXT
, ul_debugobj(cxt
, "preparing target path"));
1905 tgt
= mnt_fs_get_target(cxt
->fs
);
1910 prefix
= mnt_context_get_target_prefix(cxt
);
1912 const char *p
= *tgt
== '/' ? tgt
+ 1 : tgt
;
1915 /* target is "/", use "/prefix" */
1916 rc
= mnt_fs_set_target(cxt
->fs
, prefix
);
1920 if (asprintf(&path
, "%s/%s", prefix
, p
) <= 0)
1923 rc
= mnt_fs_set_target(cxt
->fs
, path
);
1929 tgt
= mnt_fs_get_target(cxt
->fs
);
1932 ns_old
= mnt_context_switch_target_ns(cxt
);
1934 return -MNT_ERR_NAMESPACE
;
1937 if (cxt
->action
== MNT_ACT_MOUNT
1938 && !mnt_context_is_restricted(cxt
)
1939 && (cxt
->user_mountflags
& MNT_MS_XCOMMENT
||
1940 cxt
->user_mountflags
& MNT_MS_XFSTABCOMM
)) {
1942 rc
= mkdir_target(tgt
, cxt
->fs
);
1944 if (!mnt_context_switch_ns(cxt
, ns_old
))
1945 return -MNT_ERR_NAMESPACE
;
1946 return rc
; /* mkdir or parse error */
1950 /* canonicalize the path */
1951 cache
= mnt_context_get_cache(cxt
);
1953 char *path
= mnt_resolve_path(tgt
, cache
);
1954 if (path
&& strcmp(path
, tgt
) != 0)
1955 rc
= mnt_fs_set_target(cxt
->fs
, path
);
1958 if (!mnt_context_switch_ns(cxt
, ns_old
))
1959 return -MNT_ERR_NAMESPACE
;
1962 DBG(CXT
, ul_debugobj(cxt
, "failed to prepare target '%s'", tgt
));
1964 DBG(CXT
, ul_debugobj(cxt
, "final target '%s'",
1965 mnt_fs_get_target(cxt
->fs
)));
1969 /* Guess type, but not set to cxt->fs, always use free() for the result. It's
1970 * no error when we're not able to guess a filesystem type. Note that error
1971 * does not mean that result in @type is NULL.
1973 int mnt_context_guess_srcpath_fstype(struct libmnt_context
*cxt
, char **type
)
1976 struct libmnt_ns
*ns_old
;
1984 dev
= mnt_fs_get_srcpath(cxt
->fs
);
1988 ns_old
= mnt_context_switch_target_ns(cxt
);
1990 return -MNT_ERR_NAMESPACE
;
1992 if (access(dev
, F_OK
) == 0) {
1993 struct libmnt_cache
*cache
= mnt_context_get_cache(cxt
);
1996 *type
= mnt_get_fstype(dev
, &ambi
, cache
);
1998 rc
= -MNT_ERR_AMBIFS
;
2000 if (cache
&& *type
) {
2001 *type
= strdup(*type
);
2006 DBG(CXT
, ul_debugobj(cxt
, "access(%s) failed [%m]", dev
));
2007 if (strchr(dev
, ':') != NULL
) {
2008 *type
= strdup("nfs");
2011 } else if (!strncmp(dev
, "//", 2)) {
2012 *type
= strdup("cifs");
2018 if (!mnt_context_switch_ns(cxt
, ns_old
))
2019 return -MNT_ERR_NAMESPACE
;
2025 * It's usually no error when we're not able to detect the filesystem type -- we
2026 * will try to use the types from /{etc,proc}/filesystems.
2028 int mnt_context_guess_fstype(struct libmnt_context
*cxt
)
2035 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
2037 DBG(CXT
, ul_debugobj(cxt
, "preparing fstype"));
2039 if ((cxt
->mountflags
& (MS_BIND
| MS_MOVE
))
2040 || mnt_context_propagation_only(cxt
))
2043 type
= (char *) mnt_fs_get_fstype(cxt
->fs
);
2044 if (type
&& !strcmp(type
, "auto")) {
2045 mnt_fs_set_fstype(cxt
->fs
, NULL
);
2051 if (cxt
->mountflags
& MS_REMOUNT
)
2053 if (cxt
->fstype_pattern
)
2056 rc
= mnt_context_guess_srcpath_fstype(cxt
, &type
);
2057 if (rc
== 0 && type
)
2058 __mnt_fs_set_fstype_ptr(cxt
->fs
, type
);
2062 DBG(CXT
, ul_debugobj(cxt
, "FS type: %s [rc=%d]",
2063 mnt_fs_get_fstype(cxt
->fs
), rc
));
2066 return mnt_fs_set_fstype(cxt
->fs
, "none");
2070 * The default is to use fstype from cxt->fs, this could be overwritten by
2071 * @type. The @act is MNT_ACT_{MOUNT,UMOUNT}.
2073 * Returns: 0 on success or negative number in case of error. Note that success
2074 * does not mean that there is any usable helper, you have to check cxt->helper.
2076 int mnt_context_prepare_helper(struct libmnt_context
*cxt
, const char *name
,
2079 char search_path
[] = FS_SEARCH_PATH
; /* from config.h */
2080 char *p
= NULL
, *path
;
2081 struct libmnt_ns
*ns_old
;
2086 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
2089 type
= mnt_fs_get_fstype(cxt
->fs
);
2091 if (type
&& strchr(type
, ','))
2092 return 0; /* type is fstype pattern */
2094 if (mnt_context_is_nohelpers(cxt
)
2096 || !strcmp(type
, "none")
2097 || strstr(type
, "/..") /* don't try to smuggle path */
2098 || mnt_fs_is_swaparea(cxt
->fs
))
2101 ns_old
= mnt_context_switch_origin_ns(cxt
);
2103 return -MNT_ERR_NAMESPACE
;
2105 /* Ignore errors when search in $PATH and do not modify
2106 * @rc due to stat() etc.
2108 path
= strtok_r(search_path
, ":", &p
);
2110 char helper
[PATH_MAX
];
2114 xrc
= snprintf(helper
, sizeof(helper
), "%s/%s.%s",
2116 path
= strtok_r(NULL
, ":", &p
);
2118 if (xrc
< 0 || (size_t) xrc
>= sizeof(helper
))
2121 xrc
= stat(helper
, &st
);
2122 if (rc
== -1 && errno
== ENOENT
&& strchr(type
, '.')) {
2123 /* If type ends with ".subtype" try without it */
2124 char *hs
= strrchr(helper
, '.');
2127 xrc
= stat(helper
, &st
);
2130 DBG(CXT
, ul_debugobj(cxt
, "%-25s ... %s", helper
,
2131 xrc
? "not found" : "found"));
2136 rc
= strdup_to_struct_member(cxt
, helper
, helper
);
2140 if (!mnt_context_switch_ns(cxt
, ns_old
))
2141 rc
= -MNT_ERR_NAMESPACE
;
2143 /* make sure helper is not set on error */
2151 int mnt_context_merge_mflags(struct libmnt_context
*cxt
)
2153 unsigned long fl
= 0;
2158 DBG(CXT
, ul_debugobj(cxt
, "merging mount flags"));
2160 rc
= mnt_context_get_mflags(cxt
, &fl
);
2163 cxt
->mountflags
= fl
;
2166 rc
= mnt_context_get_user_mflags(cxt
, &fl
);
2169 cxt
->user_mountflags
= fl
;
2171 DBG(CXT
, ul_debugobj(cxt
, "final flags: VFS=%08lx user=%08lx",
2172 cxt
->mountflags
, cxt
->user_mountflags
));
2174 cxt
->flags
|= MNT_FL_MOUNTFLAGS_MERGED
;
2179 * Prepare /etc/mtab or /run/mount/utab
2181 int mnt_context_prepare_update(struct libmnt_context
*cxt
)
2188 assert(cxt
->action
);
2189 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
2191 DBG(CXT
, ul_debugobj(cxt
, "prepare update"));
2193 if (mnt_context_propagation_only(cxt
)) {
2194 DBG(CXT
, ul_debugobj(cxt
, "skip update: only MS_PROPAGATION"));
2198 target
= mnt_fs_get_target(cxt
->fs
);
2200 if (cxt
->action
== MNT_ACT_UMOUNT
&& target
&& !strcmp(target
, "/")) {
2201 DBG(CXT
, ul_debugobj(cxt
, "root umount: setting NOMTAB"));
2202 mnt_context_disable_mtab(cxt
, TRUE
);
2204 if (mnt_context_is_nomtab(cxt
)) {
2205 DBG(CXT
, ul_debugobj(cxt
, "skip update: NOMTAB flag"));
2208 if (!mnt_context_get_writable_tabpath(cxt
)) {
2209 DBG(CXT
, ul_debugobj(cxt
, "skip update: no writable destination"));
2212 /* 0 = success, 1 = not called yet */
2213 if (cxt
->syscall_status
!= 1 && cxt
->syscall_status
!= 0) {
2214 DBG(CXT
, ul_debugobj(cxt
,
2215 "skip update: syscall failed [status=%d]",
2216 cxt
->syscall_status
));
2221 const char *name
= mnt_context_get_writable_tabpath(cxt
);
2223 if (cxt
->action
== MNT_ACT_UMOUNT
&& is_file_empty(name
)) {
2224 DBG(CXT
, ul_debugobj(cxt
,
2225 "skip update: umount, no table"));
2229 cxt
->update
= mnt_new_update();
2233 mnt_update_set_filename(cxt
->update
, name
,
2234 !mnt_context_mtab_writable(cxt
));
2237 if (cxt
->action
== MNT_ACT_UMOUNT
)
2238 rc
= mnt_update_set_fs(cxt
->update
, cxt
->mountflags
,
2239 mnt_context_get_target(cxt
), NULL
);
2241 rc
= mnt_update_set_fs(cxt
->update
, cxt
->mountflags
,
2244 return rc
< 0 ? rc
: 0;
2247 int mnt_context_update_tabs(struct libmnt_context
*cxt
)
2251 struct libmnt_ns
*ns_old
;
2255 if (mnt_context_is_nomtab(cxt
)) {
2256 DBG(CXT
, ul_debugobj(cxt
, "don't update: NOMTAB flag"));
2259 if (!cxt
->update
|| !mnt_update_is_ready(cxt
->update
)) {
2260 DBG(CXT
, ul_debugobj(cxt
, "don't update: no update prepared"));
2264 ns_old
= mnt_context_switch_target_ns(cxt
);
2266 return -MNT_ERR_NAMESPACE
;
2268 /* check utab update when external helper executed */
2269 if (mnt_context_helper_executed(cxt
)
2270 && mnt_context_get_helper_status(cxt
) == 0
2271 && mnt_context_utab_writable(cxt
)) {
2273 if (mnt_update_already_done(cxt
->update
, cxt
->lock
)) {
2274 DBG(CXT
, ul_debugobj(cxt
, "don't update: error evaluate or already updated"));
2277 } else if (cxt
->helper
) {
2278 DBG(CXT
, ul_debugobj(cxt
, "don't update: external helper"));
2282 if (cxt
->syscall_status
!= 0
2283 && !(mnt_context_helper_executed(cxt
) &&
2284 mnt_context_get_helper_status(cxt
) == 0)) {
2286 DBG(CXT
, ul_debugobj(cxt
, "don't update: syscall/helper failed/not called"));
2290 fl
= mnt_update_get_mflags(cxt
->update
);
2291 if ((cxt
->mountflags
& MS_RDONLY
) != (fl
& MS_RDONLY
))
2293 * fix MS_RDONLY in options
2295 mnt_update_force_rdonly(cxt
->update
,
2296 cxt
->mountflags
& MS_RDONLY
);
2298 rc
= mnt_update_table(cxt
->update
, cxt
->lock
);
2301 if (!mnt_context_switch_ns(cxt
, ns_old
))
2302 return -MNT_ERR_NAMESPACE
;
2306 /* apply @fs to @cxt -- use mnt_context_apply_fstab() if not sure
2308 int mnt_context_apply_fs(struct libmnt_context
*cxt
, struct libmnt_fs
*fs
)
2312 if (!cxt
->optsmode
) {
2313 if (mnt_context_is_restricted(cxt
)) {
2314 DBG(CXT
, ul_debugobj(cxt
, "force fstab usage for non-root users!"));
2315 cxt
->optsmode
= MNT_OMODE_USER
;
2317 DBG(CXT
, ul_debugobj(cxt
, "use default optsmode"));
2318 cxt
->optsmode
= MNT_OMODE_AUTO
;
2322 DBG(CXT
, ul_debugobj(cxt
, "apply entry:"));
2323 DBG(CXT
, mnt_fs_print_debug(fs
, stderr
));
2324 DBG(CXT
, ul_debugobj(cxt
, "OPTSMODE (opt-part): ignore=%d, append=%d, prepend=%d, replace=%d",
2325 cxt
->optsmode
& MNT_OMODE_IGNORE
? 1 : 0,
2326 cxt
->optsmode
& MNT_OMODE_APPEND
? 1 : 0,
2327 cxt
->optsmode
& MNT_OMODE_PREPEND
? 1 : 0,
2328 cxt
->optsmode
& MNT_OMODE_REPLACE
? 1 : 0));
2330 /* copy from fs to our FS description
2332 rc
= mnt_fs_set_source(cxt
->fs
, mnt_fs_get_source(fs
));
2334 rc
= mnt_fs_set_target(cxt
->fs
, mnt_fs_get_target(fs
));
2336 if (!rc
&& !mnt_fs_get_fstype(cxt
->fs
))
2337 rc
= mnt_fs_set_fstype(cxt
->fs
, mnt_fs_get_fstype(fs
));
2339 if (!rc
&& !mnt_fs_get_root(cxt
->fs
) && mnt_fs_get_root(fs
))
2340 rc
= mnt_fs_set_root(cxt
->fs
, mnt_fs_get_root(fs
));
2345 if (cxt
->optsmode
& MNT_OMODE_IGNORE
)
2347 else if (cxt
->optsmode
& MNT_OMODE_REPLACE
)
2348 rc
= mnt_fs_set_options(cxt
->fs
, mnt_fs_get_options(fs
));
2350 else if (cxt
->optsmode
& MNT_OMODE_APPEND
)
2351 rc
= mnt_fs_append_options(cxt
->fs
, mnt_fs_get_options(fs
));
2353 else if (cxt
->optsmode
& MNT_OMODE_PREPEND
)
2354 rc
= mnt_fs_prepend_options(cxt
->fs
, mnt_fs_get_options(fs
));
2357 cxt
->flags
|= MNT_FL_TAB_APPLIED
;
2360 DBG(CXT
, ul_debugobj(cxt
, "final entry [rc=%d]:", rc
));
2361 DBG(CXT
, mnt_fs_print_debug(cxt
->fs
, stderr
));
2366 static int apply_table(struct libmnt_context
*cxt
, struct libmnt_table
*tb
,
2369 struct libmnt_fs
*fs
= NULL
;
2370 const char *src
, *tgt
;
2375 src
= mnt_fs_get_source(cxt
->fs
);
2376 tgt
= mnt_fs_get_target(cxt
->fs
);
2379 fs
= mnt_table_find_pair(tb
, src
, tgt
, direction
);
2382 fs
= mnt_table_find_source(tb
, src
, direction
);
2384 fs
= mnt_table_find_target(tb
, tgt
, direction
);
2386 if (!fs
&& mnt_context_is_swapmatch(cxt
)) {
2387 /* swap source and target (if @src is not LABEL/UUID),
2392 * the path could be a mountpoint as well as a source (for
2393 * example bind mount, symlink to a device, ...).
2395 if (src
&& !mnt_fs_get_tag(cxt
->fs
, NULL
, NULL
))
2396 fs
= mnt_table_find_target(tb
, src
, direction
);
2398 fs
= mnt_table_find_source(tb
, tgt
, direction
);
2403 return -MNT_ERR_NOFSTAB
; /* not found */
2405 return mnt_context_apply_fs(cxt
, fs
);
2409 * mnt_context_apply_fstab:
2410 * @cxt: mount context
2412 * This function is optional.
2414 * Returns: 0 on success, negative number in case of error.
2416 int mnt_context_apply_fstab(struct libmnt_context
*cxt
)
2418 int rc
= -1, isremount
= 0, iscmdbind
= 0;
2419 struct libmnt_ns
*ns_old
;
2420 struct libmnt_table
*tab
= NULL
;
2421 const char *src
= NULL
, *tgt
= NULL
;
2422 unsigned long mflags
= 0;
2424 if (!cxt
|| !cxt
->fs
)
2427 if (mnt_context_tab_applied(cxt
)) { /* already applied */
2428 DBG(CXT
, ul_debugobj(cxt
, "fstab already applied -- skip"));
2432 if (mnt_context_is_restricted(cxt
)) {
2433 DBG(CXT
, ul_debugobj(cxt
, "force fstab usage for non-root users!"));
2434 cxt
->optsmode
= MNT_OMODE_USER
;
2435 } else if (cxt
->optsmode
== 0) {
2436 DBG(CXT
, ul_debugobj(cxt
, "use default optsmode"));
2437 cxt
->optsmode
= MNT_OMODE_AUTO
;
2438 } else if (cxt
->optsmode
& MNT_OMODE_NOTAB
) {
2439 cxt
->optsmode
&= ~MNT_OMODE_FSTAB
;
2440 cxt
->optsmode
&= ~MNT_OMODE_MTAB
;
2441 cxt
->optsmode
&= ~MNT_OMODE_FORCE
;
2444 if (mnt_context_get_mflags(cxt
, &mflags
) == 0) {
2445 isremount
= !!(mflags
& MS_REMOUNT
);
2446 iscmdbind
= !!(mflags
& MS_BIND
);
2450 src
= mnt_fs_get_source(cxt
->fs
);
2451 tgt
= mnt_fs_get_target(cxt
->fs
);
2454 DBG(CXT
, ul_debugobj(cxt
, "OPTSMODE (file-part): force=%d, fstab=%d, mtab=%d",
2455 cxt
->optsmode
& MNT_OMODE_FORCE
? 1 : 0,
2456 cxt
->optsmode
& MNT_OMODE_FSTAB
? 1 : 0,
2457 cxt
->optsmode
& MNT_OMODE_MTAB
? 1 : 0));
2459 /* fstab is not required if source and target are specified */
2460 if (src
&& tgt
&& !(cxt
->optsmode
& MNT_OMODE_FORCE
)) {
2461 DBG(CXT
, ul_debugobj(cxt
, "fstab not required -- skip"));
2466 && !(cxt
->optsmode
& MNT_OMODE_FSTAB
)
2467 && !(cxt
->optsmode
& MNT_OMODE_MTAB
)) {
2468 DBG(CXT
, ul_debugobj(cxt
, "only target; fstab/mtab not required "
2469 "-- skip, probably MS_PROPAGATION"));
2473 /* let's initialize cxt->fs */
2474 ignore_result( mnt_context_get_fs(cxt
) );
2476 ns_old
= mnt_context_switch_target_ns(cxt
);
2478 return -MNT_ERR_NAMESPACE
;
2481 if (cxt
->optsmode
& MNT_OMODE_FSTAB
) {
2482 DBG(CXT
, ul_debugobj(cxt
, "trying to apply fstab (src=%s, target=%s)", src
, tgt
));
2483 rc
= mnt_context_get_fstab(cxt
, &tab
);
2485 rc
= apply_table(cxt
, tab
, MNT_ITER_FORWARD
);
2489 if (rc
< 0 && (cxt
->optsmode
& MNT_OMODE_MTAB
)
2490 && (isremount
|| cxt
->action
== MNT_ACT_UMOUNT
)) {
2491 DBG(CXT
, ul_debugobj(cxt
, "trying to apply mtab (src=%s, target=%s)", src
, tgt
));
2493 rc
= mnt_context_get_mtab_for_target(cxt
, &tab
, tgt
);
2495 rc
= mnt_context_get_mtab(cxt
, &tab
);
2497 rc
= apply_table(cxt
, tab
, MNT_ITER_BACKWARD
);
2500 if (!mnt_context_switch_ns(cxt
, ns_old
))
2501 return -MNT_ERR_NAMESPACE
;
2504 if (!mnt_context_is_restricted(cxt
)
2507 DBG(CXT
, ul_debugobj(cxt
, "only target; ignore missing mtab entry on remount"));
2511 DBG(CXT
, ul_debugobj(cxt
, "failed to find entry in fstab/mtab [rc=%d]: %m", rc
));
2513 /* force to "not found in fstab/mtab" error, the details why
2514 * not found are not so important and may be misinterpreted by
2515 * applications... */
2516 rc
= -MNT_ERR_NOFSTAB
;
2519 } else if (isremount
&& !iscmdbind
) {
2521 /* remove "bind" from fstab (or no-op if not present) */
2522 mnt_optstr_remove_option(&cxt
->fs
->optstr
, "bind");
2528 * mnt_context_tab_applied:
2529 * @cxt: mount context
2531 * Returns: 1 if fstab (or mtab) has been applied to the context, or 0.
2533 int mnt_context_tab_applied(struct libmnt_context
*cxt
)
2535 return cxt
->flags
& MNT_FL_TAB_APPLIED
;
2539 * This is not a public function!
2541 * Returns 1 if *only propagation flags* change is requested.
2543 int mnt_context_propagation_only(struct libmnt_context
*cxt
)
2545 if (cxt
->action
!= MNT_ACT_MOUNT
)
2548 /* has to be called after context_mount.c: fix_opts() */
2549 assert((cxt
->flags
& MNT_FL_MOUNTOPTS_FIXED
));
2551 /* all propagation mounts are in cxt->addmount */
2552 return !list_empty(&cxt
->addmounts
)
2553 && (cxt
->mountflags
== 0 || cxt
->mountflags
== MS_SILENT
)
2555 && (!cxt
->fs
->fstype
|| strcmp(cxt
->fs
->fstype
, "none") == 0)
2556 && (!cxt
->fs
->source
|| strcmp(cxt
->fs
->source
, "none") == 0);
2560 * mnt_context_get_status:
2561 * @cxt: mount context
2563 * Global libmount status.
2565 * The real exit code of the mount.type helper has to be tested by
2566 * mnt_context_get_helper_status(). The mnt_context_get_status() only informs
2567 * that exec() has been successful.
2569 * Returns: 1 if mount.type or mount(2) syscall has been successfully called.
2571 int mnt_context_get_status(struct libmnt_context
*cxt
)
2573 return !cxt
->syscall_status
|| !cxt
->helper_exec_status
;
2577 * mnt_context_helper_executed:
2578 * @cxt: mount context
2580 * Returns: 1 if mount.type helper has been executed, or 0.
2582 int mnt_context_helper_executed(struct libmnt_context
*cxt
)
2584 return cxt
->helper_exec_status
!= 1;
2588 * mnt_context_get_helper_status:
2589 * @cxt: mount context
2591 * Return: mount.type helper exit status, result is reliable only if
2592 * mnt_context_helper_executed() returns 1.
2594 int mnt_context_get_helper_status(struct libmnt_context
*cxt
)
2596 return cxt
->helper_status
;
2600 * mnt_context_syscall_called:
2601 * @cxt: mount context
2603 * Returns: 1 if mount(2) syscall has been called, or 0.
2605 int mnt_context_syscall_called(struct libmnt_context
*cxt
)
2607 return cxt
->syscall_status
!= 1;
2611 * mnt_context_get_syscall_errno:
2612 * @cxt: mount context
2614 * The result from this function is reliable only if
2615 * mnt_context_syscall_called() returns 1.
2617 * Returns: mount(2) errno if the syscall failed or 0.
2619 int mnt_context_get_syscall_errno(struct libmnt_context
*cxt
)
2621 if (cxt
->syscall_status
< 0)
2622 return -cxt
->syscall_status
;
2627 * mnt_context_set_syscall_status:
2628 * @cxt: mount context
2629 * @status: mount(2) status
2631 * The @status should be 0 on success, or negative number on error (-errno).
2633 * This function should only be used if the [u]mount(2) syscall is NOT called by
2636 * Returns: 0 or negative number in case of error.
2638 int mnt_context_set_syscall_status(struct libmnt_context
*cxt
, int status
)
2643 DBG(CXT
, ul_debugobj(cxt
, "syscall status set to: %d", status
));
2644 cxt
->syscall_status
= status
;
2649 * mnt_context_strerror
2652 * @bufsiz: size of the buffer
2654 * Not implemented, deprecated in favor or mnt_context_get_excode().
2656 * Returns: 0 or negative number in case of error.
2658 int mnt_context_strerror(struct libmnt_context
*cxt
__attribute__((__unused__
)),
2659 char *buf
__attribute__((__unused__
)),
2660 size_t bufsiz
__attribute__((__unused__
)))
2662 /* TODO: based on cxt->syscall_errno or cxt->helper_status */
2667 int mnt_context_get_generic_excode(int rc
, char *buf
, size_t bufsz
, char *fmt
, ...)
2672 return MNT_EX_SUCCESS
;
2676 /* we need to support "%m" */
2677 errno
= rc
< 0 ? -rc
: rc
;
2680 vsnprintf(buf
, bufsz
, fmt
, va
);
2699 * mnt_context_get_excode:
2701 * @rc: return code of the previous operation
2702 * @buf: buffer to print error message (optional)
2703 * @bufsz: size of the buffer
2705 * This function analyzes context, [u]mount syscall and external helper status
2706 * and @mntrc and generates unified return code (see MNT_EX_*) as expected
2707 * from mount(8) or umount(8).
2709 * If the external helper (e.g. /sbin/mount.type) has been executed than it
2710 * returns status from wait() of the helper. It's not libmount fail if helper
2711 * returns some crazy undocumented codes... See mnt_context_helper_executed()
2712 * and mnt_context_get_helper_status(). Note that mount(8) and umount(8) utils
2713 * always return code from helper without extra care about it.
2715 * If the argument @buf is not NULL then error message is generated (if
2718 * The @mntrc is usually return code from mnt_context_mount(),
2719 * mnt_context_umount(), or 'mntrc' as returned by mnt_context_next_mount().
2723 * Returns: MNT_EX_* codes.
2725 int mnt_context_get_excode(
2726 struct libmnt_context
*cxt
,
2732 *buf
= '\0'; /* for sure */
2734 if (!cxt
->enabled_textdomain
) {
2735 bindtextdomain(LIBMOUNT_TEXTDOMAIN
, LOCALEDIR
);
2736 cxt
->enabled_textdomain
= 1;
2740 switch (cxt
->action
) {
2742 rc
= mnt_context_get_mount_excode(cxt
, rc
, buf
, bufsz
);
2744 case MNT_ACT_UMOUNT
:
2745 rc
= mnt_context_get_umount_excode(cxt
, rc
, buf
, bufsz
);
2749 rc
= mnt_context_get_generic_excode(rc
, buf
, bufsz
,
2750 _("operation failed: %m"));
2752 rc
= MNT_EX_SUCCESS
;
2756 DBG(CXT
, ul_debugobj(cxt
, "excode: rc=%d message=\"%s\"", rc
,
2757 buf
? buf
: "<no-message>"));
2763 * mnt_context_init_helper
2764 * @cxt: mount context
2765 * @action: MNT_ACT_{UMOUNT,MOUNT}
2766 * @flags: not used now
2768 * This function informs libmount that used from [u]mount.type helper.
2770 * The function also calls mnt_context_disable_helpers() to avoid recursive
2771 * mount.type helpers calling. It you really want to call another
2772 * mount.type helper from your helper, then you have to explicitly enable this
2775 * mnt_context_disable_helpers(cxt, FALSE);
2777 * Returns: 0 on success, negative number in case of error.
2779 int mnt_context_init_helper(struct libmnt_context
*cxt
, int action
,
2780 int flags
__attribute__((__unused__
)))
2787 rc
= mnt_context_disable_helpers(cxt
, TRUE
);
2789 rc
= set_flag(cxt
, MNT_FL_HELPER
, 1);
2791 cxt
->action
= action
;
2793 DBG(CXT
, ul_debugobj(cxt
, "initialized for [u]mount.<type> helper [rc=%d]", rc
));
2798 * mnt_context_helper_setopt:
2800 * @c: getopt() result
2801 * @arg: getopt() optarg
2803 * This function applies the [u]mount.type command line option (for example parsed
2804 * by getopt or getopt_long) to @cxt. All unknown options are ignored and
2805 * then 1 is returned.
2807 * Returns: negative number on error, 1 if @c is unknown option, 0 on success.
2809 int mnt_context_helper_setopt(struct libmnt_context
*cxt
, int c
, char *arg
)
2812 switch(cxt
->action
) {
2814 return mnt_context_mount_setopt(cxt
, c
, arg
);
2815 case MNT_ACT_UMOUNT
:
2816 return mnt_context_umount_setopt(cxt
, c
, arg
);
2823 * mnt_context_is_fs_mounted:
2826 * @mounted: returns 1 for mounted and 0 for non-mounted filesystems
2828 * Please, read the mnt_table_is_fs_mounted() description!
2830 * Returns: 0 on success and negative number in case of error.
2832 int mnt_context_is_fs_mounted(struct libmnt_context
*cxt
,
2833 struct libmnt_fs
*fs
, int *mounted
)
2835 struct libmnt_table
*mtab
, *orig
;
2837 struct libmnt_ns
*ns_old
;
2839 if (!cxt
|| !fs
|| !mounted
)
2842 ns_old
= mnt_context_switch_target_ns(cxt
);
2844 return -MNT_ERR_NAMESPACE
;
2847 rc
= mnt_context_get_mtab(cxt
, &mtab
);
2848 if (rc
== -ENOENT
&& mnt_fs_streq_target(fs
, "/proc") &&
2849 (!cxt
->mtab_path
|| startswith(cxt
->mtab_path
, "/proc/"))) {
2851 mnt_unref_table(cxt
->mtab
);
2855 return 0; /* /proc not mounted */
2859 *mounted
= __mnt_table_is_fs_mounted(mtab
, fs
,
2860 mnt_context_get_target_prefix(cxt
));
2862 if (!mnt_context_switch_ns(cxt
, ns_old
))
2863 return -MNT_ERR_NAMESPACE
;
2867 static int mnt_context_add_child(struct libmnt_context
*cxt
, pid_t pid
)
2874 pids
= realloc(cxt
->children
, sizeof(pid_t
) * cxt
->nchildren
+ 1);
2878 DBG(CXT
, ul_debugobj(cxt
, "add new child %d", pid
));
2879 cxt
->children
= pids
;
2880 cxt
->children
[cxt
->nchildren
++] = pid
;
2885 int mnt_fork_context(struct libmnt_context
*cxt
)
2891 if (!mnt_context_is_parent(cxt
))
2894 DBG(CXT
, ul_debugobj(cxt
, "forking context"));
2901 case -1: /* error */
2902 DBG(CXT
, ul_debugobj(cxt
, "fork failed %m"));
2906 cxt
->pid
= getpid();
2907 mnt_context_enable_fork(cxt
, FALSE
);
2908 DBG(CXT
, ul_debugobj(cxt
, "child created"));
2912 rc
= mnt_context_add_child(cxt
, pid
);
2919 int mnt_context_wait_for_children(struct libmnt_context
*cxt
,
2920 int *nchildren
, int *nerrs
)
2927 assert(mnt_context_is_parent(cxt
));
2929 for (i
= 0; i
< cxt
->nchildren
; i
++) {
2930 pid_t pid
= cxt
->children
[i
];
2931 int rc
= 0, ret
= 0;
2936 DBG(CXT
, ul_debugobj(cxt
,
2937 "waiting for child (%d/%d): %d",
2938 i
+ 1, cxt
->nchildren
, pid
));
2940 rc
= waitpid(pid
, &ret
, 0);
2942 } while (rc
== -1 && errno
== EINTR
);
2947 if (rc
!= -1 && nerrs
) {
2949 (*nerrs
) += WEXITSTATUS(ret
) == 0 ? 0 : 1;
2953 cxt
->children
[i
] = 0;
2957 free(cxt
->children
);
2958 cxt
->children
= NULL
;
2962 static void close_ns(struct libmnt_ns
*ns
)
2970 mnt_unref_cache(ns
->cache
);
2975 * mnt_context_set_target_ns:
2976 * @cxt: mount context
2977 * @path: path to target namespace or NULL
2979 * Sets target namespace to namespace represented by @path. If @path is NULL,
2980 * target namespace is cleared.
2982 * This function sets errno to ENOSYS and returns error if libmount is
2983 * compiled without namespaces support.
2985 * Returns: 0 on success, negative number in case of error.
2989 int mnt_context_set_target_ns(struct libmnt_context
*cxt
, const char *path
)
2994 DBG(CXT
, ul_debugobj(cxt
, "Setting %s as target namespace", path
));
2998 close_ns(&cxt
->ns_orig
);
2999 close_ns(&cxt
->ns_tgt
);
3003 #ifdef USE_LIBMOUNT_SUPPORT_NAMESPACES
3009 /* open original namespace */
3010 if (cxt
->ns_orig
.fd
== -1) {
3011 cxt
->ns_orig
.fd
= open("/proc/self/ns/mnt", O_RDONLY
| O_CLOEXEC
);
3012 if (cxt
->ns_orig
.fd
== -1)
3014 cxt
->ns_orig
.cache
= NULL
;
3017 /* open target (wanted) namespace */
3018 tmp
= open(path
, O_RDONLY
| O_CLOEXEC
);
3022 /* test whether namespace switching works */
3023 DBG(CXT
, ul_debugobj(cxt
, "Trying whether namespace is valid"));
3024 if (setns(tmp
, CLONE_NEWNS
)
3025 || setns(cxt
->ns_orig
.fd
, CLONE_NEWNS
)) {
3027 DBG(CXT
, ul_debugobj(cxt
, "setns(2) failed [errno=%d %m]", errno
));
3031 close_ns(&cxt
->ns_tgt
);
3033 cxt
->ns_tgt
.fd
= tmp
;
3034 cxt
->ns_tgt
.cache
= NULL
;
3041 #else /* ! USE_LIBMOUNT_SUPPORT_NAMESPACES */
3048 * mnt_context_get_target_ns:
3049 * @cxt: mount context
3051 * Returns: pointer to target namespace
3055 struct libmnt_ns
*mnt_context_get_target_ns(struct libmnt_context
*cxt
)
3057 return &cxt
->ns_tgt
;
3061 * mnt_context_get_origin_ns:
3062 * @cxt: mount context
3064 * Returns: pointer to original namespace
3068 struct libmnt_ns
*mnt_context_get_origin_ns(struct libmnt_context
*cxt
)
3070 return &cxt
->ns_orig
;
3075 * mnt_context_switch_ns:
3076 * @cxt: mount context
3077 * @ns: namespace to switch to
3079 * Switch to namespace specified by ns
3084 * struct libmnt_ns *ns_old;
3085 * ns_old = mnt_context_switch_ns(cxt, mnt_context_get_target_ns(cxt));
3087 * mnt_context_switch_ns(cxt, ns_old);
3089 * </informalexample>
3091 * Returns: pointer to previous namespace or NULL on error
3095 struct libmnt_ns
*mnt_context_switch_ns(struct libmnt_context
*cxt
, struct libmnt_ns
*ns
)
3097 struct libmnt_ns
*old
= NULL
;
3103 * If mnt_context_set_target_ns() has never been used than @ns file
3104 * descriptor is -1 and this function is noop.
3107 if (ns
== old
|| ns
->fd
== -1)
3110 #ifdef USE_LIBMOUNT_SUPPORT_NAMESPACES
3111 /* remember the curremt cache */
3112 if (old
->cache
!= cxt
->cache
) {
3113 mnt_unref_cache(old
->cache
);
3114 old
->cache
= cxt
->cache
;
3115 mnt_ref_cache(old
->cache
);
3119 DBG(CXT
, ul_debugobj(cxt
, "Switching to %s namespace",
3120 ns
== mnt_context_get_target_ns(cxt
) ? "target" :
3121 ns
== mnt_context_get_origin_ns(cxt
) ? "original" : "other"));
3123 if (setns(ns
->fd
, CLONE_NEWNS
)) {
3126 DBG(CXT
, ul_debugobj(cxt
, "setns(2) failed [errno=%d %m]", errno
));
3131 /* update pointer to the current namespace */
3134 /* update pointer to the cache */
3135 mnt_unref_cache(cxt
->cache
);
3136 cxt
->cache
= ns
->cache
;
3137 mnt_ref_cache(cxt
->cache
);
3138 #endif /* USE_LIBMOUNT_SUPPORT_NAMESPACES */
3144 * mnt_context_switch_origin_ns:
3145 * @cxt: mount context
3147 * Switch to original namespace
3149 * This is shorthand for
3152 * mnt_context_switch_ns(cxt, mnt_context_get_origin_ns(cxt));
3154 * </informalexample>
3156 * Returns: pointer to previous namespace or NULL on error
3160 struct libmnt_ns
*mnt_context_switch_origin_ns(struct libmnt_context
*cxt
)
3162 return mnt_context_switch_ns(cxt
, mnt_context_get_origin_ns(cxt
));
3166 * mnt_context_switch_target_ns:
3167 * @cxt: mount context
3169 * Switch to target namespace
3171 * This is shorthand for
3174 * mnt_context_switch_ns(cxt, mnt_context_get_target_ns(cxt));
3176 * </informalexample>
3178 * Returns: pointer to previous namespace or NULL on error
3182 struct libmnt_ns
*mnt_context_switch_target_ns(struct libmnt_context
*cxt
)
3184 return mnt_context_switch_ns(cxt
, mnt_context_get_target_ns(cxt
));
3190 static int test_search_helper(struct libmnt_test
*ts
, int argc
, char *argv
[])
3192 struct libmnt_context
*cxt
;
3199 cxt
= mnt_new_context();
3205 mnt_context_get_fs(cxt
); /* just to fill cxt->fs */
3206 cxt
->flags
|= MNT_FL_MOUNTFLAGS_MERGED
; /* fake */
3208 rc
= mnt_context_prepare_helper(cxt
, "mount", type
);
3209 printf("helper is: %s\n", cxt
->helper
? cxt
->helper
: "not found");
3211 mnt_free_context(cxt
);
3216 static struct libmnt_lock
*lock
;
3218 static void lock_fallback(void)
3221 mnt_unlock_file(lock
);
3224 static int test_mount(struct libmnt_test
*ts
, int argc
, char *argv
[])
3226 int idx
= 1, rc
= 0;
3227 struct libmnt_context
*cxt
;
3232 cxt
= mnt_new_context();
3236 if (!strcmp(argv
[idx
], "-o")) {
3237 mnt_context_set_options(cxt
, argv
[idx
+ 1]);
3240 if (!strcmp(argv
[idx
], "-t")) {
3241 /* TODO: use mnt_context_set_fstype_pattern() */
3242 mnt_context_set_fstype(cxt
, argv
[idx
+ 1]);
3246 if (argc
== idx
+ 1)
3247 /* mount <mountpoint>|<device> */
3248 mnt_context_set_target(cxt
, argv
[idx
++]);
3250 else if (argc
== idx
+ 2) {
3251 /* mount <device> <mountpoint> */
3252 mnt_context_set_source(cxt
, argv
[idx
++]);
3253 mnt_context_set_target(cxt
, argv
[idx
++]);
3256 /* this is unnecessary! -- libmount is able to internally
3257 * create and manage the lock
3259 lock
= mnt_context_get_lock(cxt
);
3261 atexit(lock_fallback
);
3263 rc
= mnt_context_mount(cxt
);
3265 warn("failed to mount");
3267 printf("successfully mounted\n");
3269 lock
= NULL
; /* because we use atexit lock_fallback */
3270 mnt_free_context(cxt
);
3274 static int test_umount(struct libmnt_test
*ts
, int argc
, char *argv
[])
3276 int idx
= 1, rc
= 0;
3277 struct libmnt_context
*cxt
;
3282 cxt
= mnt_new_context();
3286 if (!strcmp(argv
[idx
], "-t")) {
3287 mnt_context_set_fstype(cxt
, argv
[idx
+ 1]);
3291 if (!strcmp(argv
[idx
], "-f")) {
3292 mnt_context_enable_force(cxt
, TRUE
);
3296 if (!strcmp(argv
[idx
], "-l")) {
3297 mnt_context_enable_lazy(cxt
, TRUE
);
3301 if (!strcmp(argv
[idx
], "-r")) {
3302 mnt_context_enable_rdonly_umount(cxt
, TRUE
);
3306 if (argc
== idx
+ 1) {
3307 /* mount <mountpoint>|<device> */
3308 mnt_context_set_target(cxt
, argv
[idx
++]);
3314 lock
= mnt_context_get_lock(cxt
);
3316 atexit(lock_fallback
);
3318 rc
= mnt_context_umount(cxt
);
3320 printf("failed to umount\n");
3322 printf("successfully umounted\n");
3324 lock
= NULL
; /* because we use atexit lock_fallback */
3325 mnt_free_context(cxt
);
3329 static int test_flags(struct libmnt_test
*ts
, int argc
, char *argv
[])
3331 int idx
= 1, rc
= 0;
3332 struct libmnt_context
*cxt
;
3333 const char *opt
= NULL
;
3334 unsigned long flags
= 0;
3339 cxt
= mnt_new_context();
3343 if (!strcmp(argv
[idx
], "-o")) {
3344 mnt_context_set_options(cxt
, argv
[idx
+ 1]);
3348 if (argc
== idx
+ 1)
3349 /* mount <mountpoint>|<device> */
3350 mnt_context_set_target(cxt
, argv
[idx
++]);
3352 rc
= mnt_context_prepare_mount(cxt
);
3354 printf("failed to prepare mount %s\n", strerror(-rc
));
3356 opt
= mnt_fs_get_options(cxt
->fs
);
3358 fprintf(stdout
, "options: %s\n", opt
);
3360 mnt_context_get_mflags(cxt
, &flags
);
3361 fprintf(stdout
, "flags: %08lx\n", flags
);
3363 mnt_free_context(cxt
);
3367 static int test_mountall(struct libmnt_test
*ts
, int argc
, char *argv
[])
3369 struct libmnt_context
*cxt
;
3370 struct libmnt_iter
*itr
;
3371 struct libmnt_fs
*fs
;
3372 int mntrc
, ignored
, idx
= 1;
3374 cxt
= mnt_new_context();
3375 itr
= mnt_new_iter(MNT_ITER_FORWARD
);
3381 if (argv
[idx
] && !strcmp(argv
[idx
], "-O")) {
3382 mnt_context_set_options_pattern(cxt
, argv
[idx
+ 1]);
3385 if (argv
[idx
] && !strcmp(argv
[idx
], "-t")) {
3386 mnt_context_set_fstype_pattern(cxt
, argv
[idx
+ 1]);
3391 while (mnt_context_next_mount(cxt
, itr
, &fs
, &mntrc
, &ignored
) == 0) {
3393 const char *tgt
= mnt_fs_get_target(fs
);
3396 printf("%s: ignored: not match\n", tgt
);
3397 else if (ignored
== 2)
3398 printf("%s: ignored: already mounted\n", tgt
);
3400 else if (!mnt_context_get_status(cxt
)) {
3403 warn("%s: mount failed", tgt
);
3405 warnx("%s: mount failed", tgt
);
3407 printf("%s: successfully mounted\n", tgt
);
3410 mnt_free_context(cxt
);
3414 int main(int argc
, char *argv
[])
3416 struct libmnt_test tss
[] = {
3417 { "--mount", test_mount
, "[-o <opts>] [-t <type>] <spec>|<src> <target>" },
3418 { "--umount", test_umount
, "[-t <type>] [-f][-l][-r] <src>|<target>" },
3419 { "--mount-all", test_mountall
, "[-O <pattern>] [-t <pattern] mount all filesystems from fstab" },
3420 { "--flags", test_flags
, "[-o <opts>] <spec>" },
3421 { "--search-helper", test_search_helper
, "<fstype>" },
3424 umask(S_IWGRP
|S_IWOTH
); /* to be compatible with mount(8) */
3426 return mnt_run_test(tss
, argc
, argv
);
3429 #endif /* TEST_PROGRAM */