]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - libmount/src/context.c
2 * Copyright (C) 2010,2011,2012 Karel Zak <kzak@redhat.com>
4 * This file may be redistributed under the terms of the
5 * GNU Lesser General Public License.
10 * @title: Library high-level context
11 * @short_description: high-level API to mount/umount devices.
15 * struct libmnt_context *cxt = mnt_new_context();
17 * mnt_context_set_options(cxt, "aaa,bbb,ccc=CCC");
18 * mnt_context_set_mflags(cxt, MS_NOATIME|MS_NOEXEC);
19 * mnt_context_set_target(cxt, "/mnt/foo");
21 * if (!mnt_context_mount(cxt))
22 * printf("successfully mounted\n");
23 * mnt_free_context(cxt);
28 * This code is similar to:
30 * mount -o aaa,bbb,ccc=CCC,noatime,noexec /mnt/foo
35 #include "fileutils.h"
42 * Returns: newly allocated mount context
44 struct libmnt_context
*mnt_new_context(void)
46 struct libmnt_context
*cxt
;
49 cxt
= calloc(1, sizeof(*cxt
));
53 INIT_LIST_HEAD(&cxt
->addmounts
);
58 mnt_context_reset_status(cxt
);
62 /* if we're really root and aren't running setuid */
63 cxt
->restricted
= (uid_t
) 0 == ruid
&& ruid
== euid
? 0 : 1;
65 DBG(CXT
, ul_debugobj(cxt
, "----> allocate %s",
66 cxt
->restricted
? "[RESTRICTED]" : ""));
76 * Deallocates context struct.
78 void mnt_free_context(struct libmnt_context
*cxt
)
83 mnt_reset_context(cxt
);
85 free(cxt
->fstype_pattern
);
86 free(cxt
->optstr_pattern
);
88 mnt_unref_table(cxt
->fstab
);
89 mnt_unref_cache(cxt
->cache
);
91 mnt_context_clear_loopdev(cxt
);
92 mnt_free_lock(cxt
->lock
);
93 mnt_free_update(cxt
->update
);
97 DBG(CXT
, ul_debugobj(cxt
, "<---- free"));
103 * @cxt: mount context
105 * Resets all information in the context that is directly related to
106 * the latest mount (spec, source, target, mount options, ...).
108 * The match patterns, cached fstab, cached canonicalized paths and tags and
109 * [e]uid are not reset. You have to use
111 * mnt_context_set_fstab(cxt, NULL);
112 * mnt_context_set_cache(cxt, NULL);
113 * mnt_context_set_fstype_pattern(cxt, NULL);
114 * mnt_context_set_options_pattern(cxt, NULL);
117 * to reset this stuff.
119 * Returns: 0 on success, negative number in case of error.
121 int mnt_reset_context(struct libmnt_context
*cxt
)
128 DBG(CXT
, ul_debugobj(cxt
, "<---- reset [status=%d] ---->",
129 mnt_context_get_status(cxt
)));
133 mnt_unref_fs(cxt
->fs
);
134 mnt_unref_table(cxt
->mtab
);
135 mnt_unref_table(cxt
->utab
);
138 free(cxt
->orig_user
);
144 cxt
->orig_user
= NULL
;
146 cxt
->user_mountflags
= 0;
147 cxt
->mountdata
= NULL
;
148 cxt
->flags
= MNT_FL_DEFAULT
;
150 /* free additional mounts list */
151 while (!list_empty(&cxt
->addmounts
)) {
152 struct libmnt_addmount
*ad
= list_entry(cxt
->addmounts
.next
,
153 struct libmnt_addmount
,
155 mnt_free_addmount(ad
);
158 mnt_context_reset_status(cxt
);
160 if (cxt
->table_fltrcb
)
161 mnt_context_set_tabfilter(cxt
, NULL
, NULL
);
163 /* restore non-resettable flags */
164 cxt
->flags
|= (fl
& MNT_FL_NOMTAB
);
165 cxt
->flags
|= (fl
& MNT_FL_FAKE
);
166 cxt
->flags
|= (fl
& MNT_FL_SLOPPY
);
167 cxt
->flags
|= (fl
& MNT_FL_VERBOSE
);
168 cxt
->flags
|= (fl
& MNT_FL_NOHELPERS
);
169 cxt
->flags
|= (fl
& MNT_FL_LOOPDEL
);
170 cxt
->flags
|= (fl
& MNT_FL_LAZY
);
171 cxt
->flags
|= (fl
& MNT_FL_FORK
);
172 cxt
->flags
|= (fl
& MNT_FL_FORCE
);
173 cxt
->flags
|= (fl
& MNT_FL_NOCANONICALIZE
);
174 cxt
->flags
|= (fl
& MNT_FL_RDONLY_UMOUNT
);
175 cxt
->flags
|= (fl
& MNT_FL_NOSWAPMATCH
);
176 cxt
->flags
|= (fl
& MNT_FL_TABPATHS_CHECKED
);
181 * mnt_context_reset_status:
184 * Resets mount(2) and mount.type statuses, so mnt_context_do_mount() or
185 * mnt_context_do_umount() could be again called with the same settings.
187 * BE CAREFUL -- after this soft reset the libmount will NOT parse mount
188 * options, evaluate permissions or apply stuff from fstab.
190 * Returns: 0 on success, negative number in case of error.
192 int mnt_context_reset_status(struct libmnt_context
*cxt
)
198 cxt
->syscall_status
= 1; /* means not called yet */
199 cxt
->helper_exec_status
= 1;
200 cxt
->helper_status
= 0;
204 static int context_init_paths(struct libmnt_context
*cxt
, int writable
)
209 cxt
->mtab_path
= mnt_get_mtab_path();
211 cxt
->utab_path
= mnt_get_utab_path();
214 return 0; /* only paths wanted */
215 if (mnt_context_is_nomtab(cxt
))
216 return 0; /* write mode overrided by mount -n */
217 if (cxt
->flags
& MNT_FL_TABPATHS_CHECKED
)
220 DBG(CXT
, ul_debugobj(cxt
, "checking for writable tab files"));
222 mnt_has_regular_mtab(&cxt
->mtab_path
, &cxt
->mtab_writable
);
224 if (!cxt
->mtab_writable
)
225 /* use /run/mount/utab if /etc/mtab is useless */
226 mnt_has_regular_utab(&cxt
->utab_path
, &cxt
->utab_writable
);
228 cxt
->flags
|= MNT_FL_TABPATHS_CHECKED
;
232 int mnt_context_mtab_writable(struct libmnt_context
*cxt
)
236 context_init_paths(cxt
, 1);
237 return cxt
->mtab_writable
== 1;
240 int mnt_context_utab_writable(struct libmnt_context
*cxt
)
244 context_init_paths(cxt
, 1);
245 return cxt
->utab_writable
== 1;
248 const char *mnt_context_get_writable_tabpath(struct libmnt_context
*cxt
)
252 context_init_paths(cxt
, 1);
253 return cxt
->mtab_writable
? cxt
->mtab_path
: cxt
->utab_path
;
257 static int set_flag(struct libmnt_context
*cxt
, int flag
, int enable
)
263 DBG(CXT
, ul_debugobj(cxt
, "enabling flag %04x", flag
));
266 DBG(CXT
, ul_debugobj(cxt
, "disabling flag %04x", flag
));
273 * mnt_context_is_restricted:
274 * @cxt: mount context
276 * Returns: 0 for an unrestricted mount (user is root), or 1 for non-root mounts
278 int mnt_context_is_restricted(struct libmnt_context
*cxt
)
280 return cxt
->restricted
;
284 * mnt_context_set_optsmode
285 * @cxt: mount context
286 * @mode: MNT_OMODE_* flags
288 * Controls how to use mount optionssource and target paths from fstab/mtab.
290 * @MNT_OMODE_IGNORE: ignore mtab/fstab options
292 * @MNT_OMODE_APPEND: append mtab/fstab options to existing options
294 * @MNT_OMODE_PREPEND: prepend mtab/fstab options to existing options
296 * @MNT_OMODE_REPLACE: replace existing options with options from mtab/fstab
298 * @MNT_OMODE_FORCE: always read mtab/fstab (although source and target are defined)
300 * @MNT_OMODE_FSTAB: read from fstab
302 * @MNT_OMODE_MTAB: read from mtab if fstab not enabled or failed
304 * @MNT_OMODE_NOTAB: do not read fstab/mtab at all
306 * @MNT_OMODE_AUTO: default mode (MNT_OMODE_PREPEND | MNT_OMODE_FSTAB | MNT_OMODE_MTAB)
308 * @MNT_OMODE_USER: default for non-root users (MNT_OMODE_REPLACE | MNT_OMODE_FORCE | MNT_OMODE_FSTAB)
312 * - MNT_OMODE_USER is always used if mount context is in restricted mode
313 * - MNT_OMODE_AUTO is used if nothing else is defined
314 * - the flags are evaluated in this order: MNT_OMODE_NOTAB, MNT_OMODE_FORCE,
315 * MNT_OMODE_FSTAB, MNT_OMODE_MTAB and then the mount options from fstab/mtab
316 * are set according to MNT_OMODE_{IGNORE,APPEND,PREPAND,REPLACE}
318 * Returns: 0 on success, negative number in case of error.
320 int mnt_context_set_optsmode(struct libmnt_context
*cxt
, int mode
)
325 cxt
->optsmode
= mode
;
330 * mnt_context_get_optsmode
331 * @cxt: mount context
333 * Returns: MNT_OMODE_* mask or zero.
336 int mnt_context_get_optsmode(struct libmnt_context
*cxt
)
339 return cxt
->optsmode
;
343 * mnt_context_disable_canonicalize:
344 * @cxt: mount context
345 * @disable: TRUE or FALSE
347 * Enable/disable paths canonicalization and tags evaluation. The libmount context
348 * canonicalizes paths when searching in fstab and when preparing source and target paths
349 * for mount(2) syscall.
351 * This fuction has an effect on the private (within context) fstab instance only
352 * (see mnt_context_set_fstab()). If you want to use an external fstab then you
353 * need to manage your private struct libmnt_cache (see mnt_table_set_cache(fstab,
356 * Returns: 0 on success, negative number in case of error.
358 int mnt_context_disable_canonicalize(struct libmnt_context
*cxt
, int disable
)
360 return set_flag(cxt
, MNT_FL_NOCANONICALIZE
, disable
);
364 * mnt_context_is_nocanonicalize:
365 * @cxt: mount context
367 * Returns: 1 if no-canonicalize mode is enabled or 0.
369 int mnt_context_is_nocanonicalize(struct libmnt_context
*cxt
)
371 return cxt
&& (cxt
->flags
& MNT_FL_NOCANONICALIZE
) ? 1 : 0;
375 * mnt_context_enable_lazy:
376 * @cxt: mount context
377 * @enable: TRUE or FALSE
379 * Enable/disable lazy umount (see umount(8) man page, option -l).
381 * Returns: 0 on success, negative number in case of error.
383 int mnt_context_enable_lazy(struct libmnt_context
*cxt
, int enable
)
385 return set_flag(cxt
, MNT_FL_LAZY
, enable
);
389 * mnt_context_is_lazy:
390 * @cxt: mount context
392 * Returns: 1 if lazy umount is enabled or 0
394 int mnt_context_is_lazy(struct libmnt_context
*cxt
)
396 return cxt
->flags
& MNT_FL_LAZY
? 1 : 0;
400 * mnt_context_enable_fork:
401 * @cxt: mount context
402 * @enable: TRUE or FALSE
404 * Enable/disable fork(2) call in mnt_context_next_mount() (see mount(8) man
407 * Returns: 0 on success, negative number in case of error.
409 int mnt_context_enable_fork(struct libmnt_context
*cxt
, int enable
)
411 return set_flag(cxt
, MNT_FL_FORK
, enable
);
415 * mnt_context_is_fork:
416 * @cxt: mount context
418 * Returns: 1 if fork (mount -F) is enabled or 0
420 int mnt_context_is_fork(struct libmnt_context
*cxt
)
422 return cxt
->flags
& MNT_FL_FORK
? 1 : 0;
426 * mnt_context_is_parent:
427 * @cxt: mount context
429 * Return: 1 if mount -F enabled and the current context is parent, or 0
431 int mnt_context_is_parent(struct libmnt_context
*cxt
)
433 return mnt_context_is_fork(cxt
) && cxt
->pid
== 0;
437 * mnt_context_is_child:
438 * @cxt: mount context
440 * Return: 1 f the current context is child, or 0
442 int mnt_context_is_child(struct libmnt_context
*cxt
)
444 /* See mnt_fork_context(), the for fork flag is always disabled
445 * for children to avoid recursive forking.
447 return !mnt_context_is_fork(cxt
) && cxt
->pid
;
451 * mnt_context_enable_rdonly_umount:
452 * @cxt: mount context
453 * @enable: TRUE or FALSE
455 * Enable/disable read-only remount on failed umount(2)
456 * (see umount(8) man page, option -r).
458 * Returns: 0 on success, negative number in case of error.
460 int mnt_context_enable_rdonly_umount(struct libmnt_context
*cxt
, int enable
)
462 return set_flag(cxt
, MNT_FL_RDONLY_UMOUNT
, enable
);
466 * mnt_context_is_rdonly_umount
467 * @cxt: mount context
469 * See also mnt_context_enable_rdonly_umount() and umount(8) man page,
472 * Returns: 1 if read-only remount failed umount(2) is enables or 0
474 int mnt_context_is_rdonly_umount(struct libmnt_context
*cxt
)
476 return cxt
->flags
& MNT_FL_RDONLY_UMOUNT
? 1 : 0;
480 * mnt_context_disable_helpers:
481 * @cxt: mount context
482 * @disable: TRUE or FALSE
484 * Enable/disable /sbin/[u]mount.* helpers (see mount(8) man page, option -i).
486 * Returns: 0 on success, negative number in case of error.
488 int mnt_context_disable_helpers(struct libmnt_context
*cxt
, int disable
)
490 return set_flag(cxt
, MNT_FL_NOHELPERS
, disable
);
494 * mnt_context_is_nohelpers
495 * @cxt: mount context
497 * Returns: 1 if helpers are disabled (mount -i) or 0
499 int mnt_context_is_nohelpers(struct libmnt_context
*cxt
)
501 return cxt
->flags
& MNT_FL_NOHELPERS
? 1 : 0;
506 * mnt_context_enable_sloppy:
507 * @cxt: mount context
508 * @enable: TRUE or FALSE
510 * Set/unset sloppy mounting (see mount(8) man page, option -s).
512 * Returns: 0 on success, negative number in case of error.
514 int mnt_context_enable_sloppy(struct libmnt_context
*cxt
, int enable
)
516 return set_flag(cxt
, MNT_FL_SLOPPY
, enable
);
520 * mnt_context_is_sloppy:
521 * @cxt: mount context
523 * Returns: 1 if sloppy flag is enabled or 0
525 int mnt_context_is_sloppy(struct libmnt_context
*cxt
)
527 return cxt
->flags
& MNT_FL_SLOPPY
? 1 : 0;
531 * mnt_context_enable_fake:
532 * @cxt: mount context
533 * @enable: TRUE or FALSE
535 * Enable/disable fake mounting (see mount(8) man page, option -f).
537 * Returns: 0 on success, negative number in case of error.
539 int mnt_context_enable_fake(struct libmnt_context
*cxt
, int enable
)
541 return set_flag(cxt
, MNT_FL_FAKE
, enable
);
545 * mnt_context_is_fake:
546 * @cxt: mount context
548 * Returns: 1 if fake flag is enabled or 0
550 int mnt_context_is_fake(struct libmnt_context
*cxt
)
552 return cxt
->flags
& MNT_FL_FAKE
? 1 : 0;
556 * mnt_context_disable_mtab:
557 * @cxt: mount context
558 * @disable: TRUE or FALSE
560 * Disable/enable mtab update (see mount(8) man page, option -n).
562 * Returns: 0 on success, negative number in case of error.
564 int mnt_context_disable_mtab(struct libmnt_context
*cxt
, int disable
)
566 return set_flag(cxt
, MNT_FL_NOMTAB
, disable
);
570 * mnt_context_is_nomtab:
571 * @cxt: mount context
573 * Returns: 1 if no-mtab is enabled or 0
575 int mnt_context_is_nomtab(struct libmnt_context
*cxt
)
577 return cxt
->flags
& MNT_FL_NOMTAB
? 1 : 0;
581 * mnt_context_disable_swapmatch:
582 * @cxt: mount context
583 * @disable: TRUE or FALSE
585 * Disable/enable swap between source and target for mount(8) if only one path
588 * Returns: 0 on success, negative number in case of error.
590 int mnt_context_disable_swapmatch(struct libmnt_context
*cxt
, int disable
)
592 return set_flag(cxt
, MNT_FL_NOSWAPMATCH
, disable
);
596 * mnt_context_is_swapmatch:
597 * @cxt: mount context
599 * Returns: 1 if swap between source and target is allowed (default is 1) or 0.
601 int mnt_context_is_swapmatch(struct libmnt_context
*cxt
)
603 return cxt
->flags
& MNT_FL_NOSWAPMATCH
? 0 : 1;
607 * mnt_context_enable_force:
608 * @cxt: mount context
609 * @enable: TRUE or FALSE
611 * Enable/disable force umounting (see umount(8) man page, option -f).
613 * Returns: 0 on success, negative number in case of error.
615 int mnt_context_enable_force(struct libmnt_context
*cxt
, int enable
)
617 return set_flag(cxt
, MNT_FL_FORCE
, enable
);
621 * mnt_context_is_force
622 * @cxt: mount context
624 * Returns: 1 if force umounting flag is enabled or 0
626 int mnt_context_is_force(struct libmnt_context
*cxt
)
628 return cxt
->flags
& MNT_FL_FORCE
? 1 : 0;
632 * mnt_context_enable_verbose:
633 * @cxt: mount context
634 * @enable: TRUE or FALSE
636 * Enable/disable verbose output (TODO: not implemented yet)
638 * Returns: 0 on success, negative number in case of error.
640 int mnt_context_enable_verbose(struct libmnt_context
*cxt
, int enable
)
642 return set_flag(cxt
, MNT_FL_VERBOSE
, enable
);
646 * mnt_context_is_verbose
647 * @cxt: mount context
649 * Returns: 1 if verbose flag is enabled or 0
651 int mnt_context_is_verbose(struct libmnt_context
*cxt
)
653 return cxt
->flags
& MNT_FL_VERBOSE
? 1 : 0;
657 * mnt_context_enable_loopdel:
658 * @cxt: mount context
659 * @enable: TRUE or FALSE
661 * Enable/disable the loop delete (destroy) after umount (see umount(8), option -d)
663 * Returns: 0 on success, negative number in case of error.
665 int mnt_context_enable_loopdel(struct libmnt_context
*cxt
, int enable
)
667 return set_flag(cxt
, MNT_FL_LOOPDEL
, enable
);
671 * mnt_context_is_loopdel:
672 * @cxt: mount context
674 * Returns: 1 if loop device should be deleted after umount (umount -d) or 0.
676 int mnt_context_is_loopdel(struct libmnt_context
*cxt
)
678 return cxt
->flags
& MNT_FL_LOOPDEL
? 1 : 0;
682 * mnt_context_set_fs:
683 * @cxt: mount context
684 * @fs: filesystem description
686 * The mount context uses private @fs by default. This function allows to
687 * overwrite the private @fs with an external instance. This function
688 * increments @fs reference counter (and deincrement reference counter of the
691 * The @fs will be modified by mnt_context_set_{source,target,options,fstype}
692 * functions, If the @fs is NULL, then all current FS specific settings (source,
693 * target, etc., exclude spec) are reset.
695 * Returns: 0 on success, negative number in case of error.
697 int mnt_context_set_fs(struct libmnt_context
*cxt
, struct libmnt_fs
*fs
)
702 mnt_ref_fs(fs
); /* new */
703 mnt_unref_fs(cxt
->fs
); /* old */
709 * mnt_context_get_fs:
710 * @cxt: mount context
712 * The FS contains the basic description of mountpoint, fs type and so on.
713 * Note that the FS is modified by mnt_context_set_{source,target,options,fstype}
716 * Returns: pointer to FS description or NULL in case of a calloc() error.
718 struct libmnt_fs
*mnt_context_get_fs(struct libmnt_context
*cxt
)
724 cxt
->fs
= mnt_new_fs();
729 * mnt_context_get_fs_userdata:
730 * @cxt: mount context
732 * Returns: pointer to userdata or NULL.
734 void *mnt_context_get_fs_userdata(struct libmnt_context
*cxt
)
737 return cxt
->fs
? mnt_fs_get_userdata(cxt
->fs
) : NULL
;
741 * mnt_context_get_fstab_userdata:
742 * @cxt: mount context
744 * Returns: pointer to userdata or NULL.
746 void *mnt_context_get_fstab_userdata(struct libmnt_context
*cxt
)
749 return cxt
->fstab
? mnt_table_get_userdata(cxt
->fstab
) : NULL
;
753 * mnt_context_get_mtab_userdata:
754 * @cxt: mount context
756 * Returns: pointer to userdata or NULL.
758 void *mnt_context_get_mtab_userdata(struct libmnt_context
*cxt
)
761 return cxt
->mtab
? mnt_table_get_userdata(cxt
->mtab
) : NULL
;
765 * mnt_context_set_source:
766 * @cxt: mount context
767 * @source: mount source (device, directory, UUID, LABEL, ...)
769 * Note that libmount does not interpret "nofail" (MNT_MS_NOFAIL)
770 * mount option. The real return code is always returned, when
771 * the device does not exist then it's usually MNT_ERR_NOSOURCE
772 * from libmount or ENOENT, ENOTDIR, ENOTBLK, ENXIO from moun(2).
774 * Returns: 0 on success, negative number in case of error.
776 int mnt_context_set_source(struct libmnt_context
*cxt
, const char *source
)
779 return mnt_fs_set_source(mnt_context_get_fs(cxt
), source
);
783 * mnt_context_get_source:
784 * @cxt: mount context
786 * Returns: returns pointer or NULL in case of error or if not set.
788 const char *mnt_context_get_source(struct libmnt_context
*cxt
)
791 return mnt_fs_get_source(mnt_context_get_fs(cxt
));
795 * mnt_context_set_target:
796 * @cxt: mount context
797 * @target: mountpoint
799 * Returns: 0 on success, negative number in case of error.
801 int mnt_context_set_target(struct libmnt_context
*cxt
, const char *target
)
804 return mnt_fs_set_target(mnt_context_get_fs(cxt
), target
);
808 * mnt_context_get_target:
809 * @cxt: mount context
811 * Returns: returns pointer or NULL in case of error or if not set.
813 const char *mnt_context_get_target(struct libmnt_context
*cxt
)
816 return mnt_fs_get_target(mnt_context_get_fs(cxt
));
820 * mnt_context_set_fstype:
821 * @cxt: mount context
822 * @fstype: filesystem type
824 * Note that the @fstype has to be a FS type. For patterns with
825 * comma-separated list of filesystems or for the "nofs" notation, use
826 * mnt_context_set_fstype_pattern().
828 * Returns: 0 on success, negative number in case of error.
830 int mnt_context_set_fstype(struct libmnt_context
*cxt
, const char *fstype
)
833 return mnt_fs_set_fstype(mnt_context_get_fs(cxt
), fstype
);
837 * mnt_context_get_fstype:
838 * @cxt: mount context
840 * Returns: pointer or NULL in case of error or if not set.
842 const char *mnt_context_get_fstype(struct libmnt_context
*cxt
)
845 return mnt_fs_get_fstype(mnt_context_get_fs(cxt
));
849 * mnt_context_set_options:
850 * @cxt: mount context
851 * @optstr: comma delimited mount options
853 * Returns: 0 on success, negative number in case of error.
855 int mnt_context_set_options(struct libmnt_context
*cxt
, const char *optstr
)
858 return mnt_fs_set_options(mnt_context_get_fs(cxt
), optstr
);
862 * mnt_context_append_options:
863 * @cxt: mount context
864 * @optstr: comma delimited mount options
866 * Returns: 0 on success, negative number in case of error.
868 int mnt_context_append_options(struct libmnt_context
*cxt
, const char *optstr
)
871 return mnt_fs_append_options(mnt_context_get_fs(cxt
), optstr
);
875 * mnt_context_get_options:
876 * @cxt: mount context
878 * This function returns mount options set by mnt_context_set_options() or
879 * mnt_context_append_options().
881 * Note that *after* mnt_context_prepare_mount(), the mount options string
882 * may also include options set by mnt_context_set_mflags() or other options
883 * generated by this library.
885 * Returns: pointer or NULL
887 const char *mnt_context_get_options(struct libmnt_context
*cxt
)
890 return mnt_fs_get_options(mnt_context_get_fs(cxt
));
894 * mnt_context_set_fstype_pattern:
895 * @cxt: mount context
896 * @pattern: FS name pattern (or NULL to reset the current setting)
898 * See mount(8), option -t.
900 * Returns: 0 on success, negative number in case of error.
902 int mnt_context_set_fstype_pattern(struct libmnt_context
*cxt
, const char *pattern
)
914 free(cxt
->fstype_pattern
);
915 cxt
->fstype_pattern
= p
;
920 * mnt_context_set_options_pattern:
921 * @cxt: mount context
922 * @pattern: options pattern (or NULL to reset the current setting)
924 * See mount(8), option -O.
926 * Returns: 0 on success, negative number in case of error.
928 int mnt_context_set_options_pattern(struct libmnt_context
*cxt
, const char *pattern
)
940 free(cxt
->optstr_pattern
);
941 cxt
->optstr_pattern
= p
;
946 * mnt_context_set_fstab:
947 * @cxt: mount context
950 * The mount context reads /etc/fstab to the private struct libmnt_table by default.
951 * This function allows to overwrite the private fstab with an external
954 * This function modify the @tb reference counter. This function does not set
955 * the cache for the @tb. You have to explicitly call mnt_table_set_cache(tb,
956 * mnt_context_get_cache(cxt));
958 * The fstab is used read-only and is not modified, it should be possible to
959 * share the fstab between more mount contexts (TODO: test it.)
961 * If the @tb argument is NULL, then the current private fstab instance is
964 * Returns: 0 on success, negative number in case of error.
966 int mnt_context_set_fstab(struct libmnt_context
*cxt
, struct libmnt_table
*tb
)
972 mnt_ref_table(tb
); /* new */
973 mnt_unref_table(cxt
->fstab
); /* old */
980 * mnt_context_get_fstab:
981 * @cxt: mount context
984 * See also mnt_table_parse_fstab() for more details about fstab.
986 * Returns: 0 on success, negative number in case of error.
988 int mnt_context_get_fstab(struct libmnt_context
*cxt
, struct libmnt_table
**tb
)
996 cxt
->fstab
= mnt_new_table();
999 if (cxt
->table_errcb
)
1000 mnt_table_set_parser_errcb(cxt
->fstab
, cxt
->table_errcb
);
1001 mnt_table_set_cache(cxt
->fstab
, mnt_context_get_cache(cxt
));
1002 rc
= mnt_table_parse_fstab(cxt
->fstab
, NULL
);
1013 * mnt_context_get_mtab:
1014 * @cxt: mount context
1017 * See also mnt_table_parse_mtab() for more details about mtab/mountinfo. The
1018 * result will be deallocated by mnt_free_context(@cxt).
1020 * Returns: 0 on success, negative number in case of error.
1022 int mnt_context_get_mtab(struct libmnt_context
*cxt
, struct libmnt_table
**tb
)
1030 context_init_paths(cxt
, 0);
1032 cxt
->mtab
= mnt_new_table();
1036 if (cxt
->table_errcb
)
1037 mnt_table_set_parser_errcb(cxt
->mtab
, cxt
->table_errcb
);
1038 if (cxt
->table_fltrcb
)
1039 mnt_table_set_parser_fltrcb(cxt
->mtab
,
1041 cxt
->table_fltrcb_data
);
1043 mnt_table_set_cache(cxt
->mtab
, mnt_context_get_cache(cxt
));
1045 /* utab already parsed, don't parse it again */
1046 rc
= __mnt_table_parse_mtab(cxt
->mtab
,
1047 cxt
->mtab_path
, cxt
->utab
);
1049 rc
= mnt_table_parse_mtab(cxt
->mtab
, cxt
->mtab_path
);
1057 DBG(CXT
, ul_debugobj(cxt
, "mtab requested [nents=%d]",
1058 mnt_table_get_nents(cxt
->mtab
)));
1063 * Allows to specify a filter for tab file entries. The filter is called by
1064 * the table parser. Currently used for mtab and utab only.
1066 int mnt_context_set_tabfilter(struct libmnt_context
*cxt
,
1067 int (*fltr
)(struct libmnt_fs
*, void *),
1074 cxt
->table_fltrcb
= fltr
;
1075 cxt
->table_fltrcb_data
= data
;
1078 mnt_table_set_parser_fltrcb(cxt
->mtab
,
1080 cxt
->table_fltrcb_data
);
1082 DBG(CXT
, ul_debugobj(cxt
, "tabfilter %s", fltr
? "ENABLED!" : "disabled"));
1087 * mnt_context_get_table:
1088 * @cxt: mount context
1089 * @filename: e.g. /proc/self/mountinfo
1090 * @tb: returns the table
1092 * This function allocates a new table and parses the @file. The parser error
1093 * callback and cache for tags and paths is set according to the @cxt setting.
1094 * See also mnt_table_parse_file().
1096 * It's strongly recommended to use the mnt_context_get_mtab() and
1097 * mnt_context_get_fstab() functions for mtab and fstab files. This function
1098 * does not care about LIBMOUNT_* env.variables and does not merge userspace
1101 * The result will NOT be deallocated by mnt_free_context(@cxt).
1103 * Returns: 0 on success, negative number in case of error.
1105 int mnt_context_get_table(struct libmnt_context
*cxt
,
1106 const char *filename
, struct libmnt_table
**tb
)
1115 *tb
= mnt_new_table();
1119 if (cxt
->table_errcb
)
1120 mnt_table_set_parser_errcb(*tb
, cxt
->table_errcb
);
1122 rc
= mnt_table_parse_file(*tb
, filename
);
1124 mnt_unref_table(*tb
);
1128 mnt_table_set_cache(*tb
, mnt_context_get_cache(cxt
));
1133 * mnt_context_set_tables_errcb
1134 * @cxt: mount context
1135 * @cb: pointer to callback function
1137 * The error callback is used for all tab files (e.g. mtab, fstab)
1138 * parsed within the context.
1140 * See also mnt_context_get_mtab(),
1141 * mnt_context_get_fstab(),
1142 * mnt_table_set_parser_errcb().
1144 * Returns: 0 on success, negative number in case of error.
1146 int mnt_context_set_tables_errcb(struct libmnt_context
*cxt
,
1147 int (*cb
)(struct libmnt_table
*tb
, const char *filename
, int line
))
1154 mnt_table_set_parser_errcb(cxt
->mtab
, cb
);
1156 mnt_table_set_parser_errcb(cxt
->fstab
, cb
);
1158 cxt
->table_errcb
= cb
;
1163 * mnt_context_set_cache:
1164 * @cxt: mount context
1165 * @cache: cache instance or nULL
1167 * The mount context maintains a private struct libmnt_cache by default. This
1168 * function allows to overwrite the private cache with an external instance.
1169 * This function increments cache reference counter.
1171 * If the @cache argument is NULL, then the current cache instance is reset.
1172 * This function apply the cache to fstab and mtab instances (if already
1175 * The old cache instance reference counter is de-incremented.
1177 * Returns: 0 on success, negative number in case of error.
1179 int mnt_context_set_cache(struct libmnt_context
*cxt
, struct libmnt_cache
*cache
)
1184 mnt_ref_cache(cache
); /* new */
1185 mnt_unref_cache(cxt
->cache
); /* old */
1190 mnt_table_set_cache(cxt
->mtab
, cache
);
1192 mnt_table_set_cache(cxt
->fstab
, cache
);
1198 * mnt_context_get_cache
1199 * @cxt: mount context
1201 * See also mnt_context_set_cache().
1203 * Returns: pointer to cache or NULL if canonicalization is disabled.
1205 struct libmnt_cache
*mnt_context_get_cache(struct libmnt_context
*cxt
)
1208 if (!cxt
|| mnt_context_is_nocanonicalize(cxt
))
1212 struct libmnt_cache
*cache
= mnt_new_cache();
1213 mnt_context_set_cache(cxt
, cache
);
1214 mnt_unref_cache(cache
);
1220 * mnt_context_set_passwd_cb:
1221 * @cxt: mount context
1222 * @get: callback to get password
1223 * @release: callback to release (delallocate) password
1225 * Sets callbacks for encryption password (e.g encrypted loopdev). This
1226 * function is deprecated (encrypted loops are no longer supported).
1228 * Returns: 0 on success, negative number in case of error.
1230 int mnt_context_set_passwd_cb(struct libmnt_context
*cxt
,
1231 char *(*get
)(struct libmnt_context
*),
1232 void (*release
)(struct libmnt_context
*, char *))
1237 cxt
->pwd_get_cb
= get
;
1238 cxt
->pwd_release_cb
= release
;
1243 * mnt_context_get_lock:
1244 * @cxt: mount context
1246 * The libmount applications don't have to care about mtab locking, but with a
1247 * small exception: the application has to be able to remove the lock file when
1248 * interrupted by signal or signals have to be ignored when the lock is locked.
1250 * The default behavior is to ignore all signals (except SIGALRM and
1251 * SIGTRAP for mtab udate) when the lock is locked. If this behavior
1252 * is unacceptable, then use:
1254 * lc = mnt_context_get_lock(cxt);
1256 * mnt_lock_block_signals(lc, FALSE);
1258 * and don't forget to call mnt_unlock_file(lc) before exit.
1260 * Returns: pointer to lock struct or NULL.
1262 struct libmnt_lock
*mnt_context_get_lock(struct libmnt_context
*cxt
)
1266 * DON'T call this function within libmount, it will always allocate
1267 * the lock. The mnt_update_* functions are able to allocate the lock
1268 * only when mtab/utab update is really necessary.
1270 if (!cxt
|| mnt_context_is_nomtab(cxt
))
1274 cxt
->lock
= mnt_new_lock(
1275 mnt_context_get_writable_tabpath(cxt
), 0);
1277 mnt_lock_block_signals(cxt
->lock
, TRUE
);
1283 * mnt_context_set_mflags:
1284 * @cxt: mount context
1285 * @flags: mount(2) flags (MS_* flags)
1287 * Sets mount flags (see mount(2) man page).
1289 * Note that mount context allows to define mount options by mount flags. It
1290 * means you can for example use
1292 * mnt_context_set_mflags(cxt, MS_NOEXEC | MS_NOSUID);
1296 * mnt_context_set_options(cxt, "noexec,nosuid");
1298 * both of these calls have the same effect.
1300 * Returns: 0 on success, negative number in case of error.
1302 int mnt_context_set_mflags(struct libmnt_context
*cxt
, unsigned long flags
)
1308 cxt
->mountflags
= flags
;
1310 if ((cxt
->flags
& MNT_FL_MOUNTOPTS_FIXED
) && cxt
->fs
)
1312 * the final mount options are already generated, refresh...
1314 return mnt_optstr_apply_flags(
1315 &cxt
->fs
->vfs_optstr
,
1317 mnt_get_builtin_optmap(MNT_LINUX_MAP
));
1323 * mnt_context_get_mflags:
1324 * @cxt: mount context
1325 * @flags: returns MS_* mount flags
1327 * Converts mount options string to MS_* flags and bitewise-OR the result with
1328 * the already defined flags (see mnt_context_set_mflags()).
1330 * Returns: 0 on success, negative number in case of error.
1332 int mnt_context_get_mflags(struct libmnt_context
*cxt
, unsigned long *flags
)
1335 struct list_head
*p
;
1343 if (!(cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
) && cxt
->fs
) {
1344 const char *o
= mnt_fs_get_options(cxt
->fs
);
1346 rc
= mnt_optstr_get_flags(o
, flags
,
1347 mnt_get_builtin_optmap(MNT_LINUX_MAP
));
1350 list_for_each(p
, &cxt
->addmounts
) {
1351 struct libmnt_addmount
*ad
=
1352 list_entry(p
, struct libmnt_addmount
, mounts
);
1354 *flags
|= ad
->mountflags
;
1358 *flags
|= cxt
->mountflags
;
1363 * mnt_context_set_user_mflags:
1364 * @cxt: mount context
1365 * @flags: mount(2) flags (MNT_MS_* flags, e.g. MNT_MS_LOOP)
1367 * Sets userspace mount flags.
1369 * See also notes for mnt_context_set_mflags().
1371 * Returns: 0 on success, negative number in case of error.
1373 int mnt_context_set_user_mflags(struct libmnt_context
*cxt
, unsigned long flags
)
1378 cxt
->user_mountflags
= flags
;
1383 * mnt_context_get_user_mflags:
1384 * @cxt: mount context
1385 * @flags: returns mount flags
1387 * Converts mount options string to MNT_MS_* flags and bitewise-OR the result
1388 * with the already defined flags (see mnt_context_set_user_mflags()).
1390 * Returns: 0 on success, negative number in case of error.
1392 int mnt_context_get_user_mflags(struct libmnt_context
*cxt
, unsigned long *flags
)
1402 if (!(cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
) && cxt
->fs
) {
1403 const char *o
= mnt_fs_get_user_options(cxt
->fs
);
1405 rc
= mnt_optstr_get_flags(o
, flags
,
1406 mnt_get_builtin_optmap(MNT_USERSPACE_MAP
));
1409 *flags
|= cxt
->user_mountflags
;
1414 * mnt_context_set_mountdata:
1415 * @cxt: mount context
1416 * @data: mount(2) data
1418 * The mount context generates mountdata from mount options by default. This
1419 * function allows to overwrite this behavior, and @data will be used instead
1422 * The libmount does not deallocate the data by mnt_free_context(). Note that
1423 * NULL is also valid mount data.
1425 * Returns: 0 on success, negative number in case of error.
1427 int mnt_context_set_mountdata(struct libmnt_context
*cxt
, void *data
)
1432 cxt
->mountdata
= data
;
1433 cxt
->flags
|= MNT_FL_MOUNTDATA
;
1438 * Translates LABEL/UUID/path to mountable path
1440 int mnt_context_prepare_srcpath(struct libmnt_context
*cxt
)
1442 const char *path
= NULL
;
1443 struct libmnt_cache
*cache
;
1444 const char *t
, *v
, *src
;
1449 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
1451 if (!cxt
|| !cxt
->fs
)
1454 DBG(CXT
, ul_debugobj(cxt
, "preparing source path"));
1456 src
= mnt_fs_get_source(cxt
->fs
);
1458 if (!src
&& mnt_context_propagation_only(cxt
))
1459 /* mount --make-{shared,private,...} */
1460 return mnt_fs_set_source(cxt
->fs
, "none");
1462 /* ignore filesystems without source or filesystems
1463 * where the source is a quasi-path (//foo/bar)
1465 if (!src
|| mnt_fs_is_netfs(cxt
->fs
))
1468 DBG(CXT
, ul_debugobj(cxt
, "srcpath '%s'", src
));
1470 cache
= mnt_context_get_cache(cxt
);
1472 if (!mnt_fs_get_tag(cxt
->fs
, &t
, &v
)) {
1474 * Source is TAG (evaluate)
1477 path
= mnt_resolve_tag(t
, v
, cache
);
1479 rc
= path
? mnt_fs_set_source(cxt
->fs
, path
) : -MNT_ERR_NOSOURCE
;
1481 } else if (cache
&& !mnt_fs_is_pseudofs(cxt
->fs
)) {
1483 * Source is PATH (canonicalize)
1485 path
= mnt_resolve_path(src
, cache
);
1486 if (path
&& strcmp(path
, src
))
1487 rc
= mnt_fs_set_source(cxt
->fs
, path
);
1491 DBG(CXT
, ul_debugobj(cxt
, "failed to prepare srcpath [rc=%d]", rc
));
1498 if ((cxt
->mountflags
& (MS_BIND
| MS_MOVE
| MS_REMOUNT
))
1499 || mnt_fs_is_pseudofs(cxt
->fs
)) {
1500 DBG(CXT
, ul_debugobj(cxt
, "REMOUNT/BIND/MOVE/pseudo FS source: %s", path
));
1505 * Initialize loop device
1507 if (mnt_context_is_loopdev(cxt
)) {
1508 rc
= mnt_context_setup_loopdev(cxt
);
1513 DBG(CXT
, ul_debugobj(cxt
, "final srcpath '%s'",
1514 mnt_fs_get_source(cxt
->fs
)));
1518 /* create a mountpoint if x-mount.mkdir[=<mode>] specified */
1519 static int mkdir_target(const char *tgt
, struct libmnt_fs
*fs
)
1530 if (mnt_optstr_get_option(fs
->user_optstr
, "x-mount.mkdir", &mstr
, &mstr_sz
) != 0)
1532 if (stat(tgt
, &st
) == 0)
1535 if (mstr
&& mstr_sz
) {
1539 mode
= strtol(mstr
, &end
, 8);
1541 if (errno
|| !end
|| mstr
+ mstr_sz
!= end
) {
1542 DBG(CXT
, ul_debug("failed to parse mkdir mode '%s'", mstr
));
1543 return -MNT_ERR_MOUNTOPT
;
1548 mode
= S_IRWXU
| /* 0755 */
1552 rc
= mkdir_p(tgt
, mode
);
1554 DBG(CXT
, ul_debug("mkdir %s failed: %m", tgt
));
1559 int mnt_context_prepare_target(struct libmnt_context
*cxt
)
1562 struct libmnt_cache
*cache
;
1567 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
1569 if (!cxt
|| !cxt
->fs
)
1572 DBG(CXT
, ul_debugobj(cxt
, "preparing target path"));
1574 tgt
= mnt_fs_get_target(cxt
->fs
);
1579 if (cxt
->action
== MNT_ACT_MOUNT
1580 && !mnt_context_is_restricted(cxt
)
1581 && cxt
->user_mountflags
& MNT_MS_XCOMMENT
) {
1583 rc
= mkdir_target(tgt
, cxt
->fs
);
1585 return rc
; /* mkdir or parse error */
1588 /* canonicalize the path */
1589 cache
= mnt_context_get_cache(cxt
);
1591 char *path
= mnt_resolve_path(tgt
, cache
);
1592 if (path
&& strcmp(path
, tgt
) != 0)
1593 rc
= mnt_fs_set_target(cxt
->fs
, path
);
1597 DBG(CXT
, ul_debugobj(cxt
, "failed to prepare target '%s'", tgt
));
1599 DBG(CXT
, ul_debugobj(cxt
, "final target '%s'",
1600 mnt_fs_get_target(cxt
->fs
)));
1604 /* Guess type, but not set to cxt->fs, use free() for the result. It's no error
1605 * when we're not able to guess a filesystem type.
1607 int mnt_context_guess_srcpath_fstype(struct libmnt_context
*cxt
, char **type
)
1610 const char *dev
= mnt_fs_get_srcpath(cxt
->fs
);
1617 if (access(dev
, F_OK
) == 0) {
1618 struct libmnt_cache
*cache
= mnt_context_get_cache(cxt
);
1621 *type
= mnt_get_fstype(dev
, &ambi
, cache
);
1623 *type
= strdup(*type
);
1625 rc
= -MNT_ERR_AMBIFS
;
1627 DBG(CXT
, ul_debugobj(cxt
, "access(%s) failed [%m]", dev
));
1628 if (strchr(dev
, ':') != NULL
)
1629 *type
= strdup("nfs");
1630 else if (!strncmp(dev
, "//", 2))
1631 *type
= strdup("cifs");
1639 * It's usually no error when we're not able to detect the filesystem type -- we
1640 * will try to use the types from /{etc,proc}/filesystems.
1642 int mnt_context_guess_fstype(struct libmnt_context
*cxt
)
1649 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
1651 if (!cxt
|| !cxt
->fs
)
1654 if ((cxt
->mountflags
& (MS_BIND
| MS_MOVE
))
1655 || mnt_context_propagation_only(cxt
))
1658 type
= (char *) mnt_fs_get_fstype(cxt
->fs
);
1659 if (type
&& !strcmp(type
, "auto")) {
1660 mnt_fs_set_fstype(cxt
->fs
, NULL
);
1666 if (cxt
->flags
& MS_REMOUNT
)
1668 if (cxt
->fstype_pattern
)
1671 rc
= mnt_context_guess_srcpath_fstype(cxt
, &type
);
1672 if (rc
== 0 && type
)
1673 __mnt_fs_set_fstype_ptr(cxt
->fs
, type
);
1677 DBG(CXT
, ul_debugobj(cxt
, "FS type: %s [rc=%d]",
1678 mnt_fs_get_fstype(cxt
->fs
), rc
));
1681 return mnt_fs_set_fstype(cxt
->fs
, "none");
1685 * The default is to use fstype from cxt->fs, this could be overwritten by
1686 * @type. The @act is MNT_ACT_{MOUNT,UMOUNT}.
1688 * Returns: 0 on success or negative number in case of error. Note that success
1689 * does not mean that there is any usable helper, you have to check cxt->helper.
1691 int mnt_context_prepare_helper(struct libmnt_context
*cxt
, const char *name
,
1694 char search_path
[] = FS_SEARCH_PATH
; /* from config.h */
1695 char *p
= NULL
, *path
;
1699 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
1702 type
= mnt_fs_get_fstype(cxt
->fs
);
1704 if (type
&& strchr(type
, ','))
1705 return 0; /* type is fstype pattern */
1707 if (mnt_context_is_nohelpers(cxt
)
1709 || !strcmp(type
, "none")
1710 || strstr(type
, "/..") /* don't try to smuggle path */
1711 || mnt_fs_is_swaparea(cxt
->fs
))
1714 path
= strtok_r(search_path
, ":", &p
);
1716 char helper
[PATH_MAX
];
1720 rc
= snprintf(helper
, sizeof(helper
), "%s/%s.%s",
1722 path
= strtok_r(NULL
, ":", &p
);
1724 if (rc
< 0 || (size_t) rc
>= sizeof(helper
))
1727 rc
= stat(helper
, &st
);
1728 if (rc
== -1 && errno
== ENOENT
&& strchr(type
, '.')) {
1729 /* If type ends with ".subtype" try without it */
1730 char *hs
= strrchr(helper
, '.');
1733 rc
= stat(helper
, &st
);
1736 DBG(CXT
, ul_debugobj(cxt
, "%-25s ... %s", helper
,
1737 rc
? "not found" : "found"));
1742 cxt
->helper
= strdup(helper
);
1751 int mnt_context_merge_mflags(struct libmnt_context
*cxt
)
1753 unsigned long fl
= 0;
1758 DBG(CXT
, ul_debugobj(cxt
, "merging mount flags"));
1760 rc
= mnt_context_get_mflags(cxt
, &fl
);
1763 cxt
->mountflags
= fl
;
1766 rc
= mnt_context_get_user_mflags(cxt
, &fl
);
1769 cxt
->user_mountflags
= fl
;
1771 DBG(CXT
, ul_debugobj(cxt
, "final flags: VFS=%08lx user=%08lx",
1772 cxt
->mountflags
, cxt
->user_mountflags
));
1774 cxt
->flags
|= MNT_FL_MOUNTFLAGS_MERGED
;
1779 * Prepare /etc/mtab or /run/mount/utab
1781 int mnt_context_prepare_update(struct libmnt_context
*cxt
)
1788 assert(cxt
->action
);
1789 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
1791 DBG(CXT
, ul_debugobj(cxt
, "prepare update"));
1793 if (mnt_context_propagation_only(cxt
)) {
1794 DBG(CXT
, ul_debugobj(cxt
, "skip update: only MS_PROPAGATION"));
1798 target
= mnt_fs_get_target(cxt
->fs
);
1800 if (cxt
->action
== MNT_ACT_UMOUNT
&& target
&& !strcmp(target
, "/"))
1801 /* Don't try to touch mtab if umounting root FS */
1802 mnt_context_disable_mtab(cxt
, TRUE
);
1804 if (mnt_context_is_nomtab(cxt
)) {
1805 DBG(CXT
, ul_debugobj(cxt
, "skip update: NOMTAB flag"));
1808 if (!mnt_context_get_writable_tabpath(cxt
)) {
1809 DBG(CXT
, ul_debugobj(cxt
, "skip update: no writable destination"));
1812 /* 0 = success, 1 = not called yet */
1813 if (cxt
->syscall_status
!= 1 && cxt
->syscall_status
!= 0) {
1814 DBG(CXT
, ul_debugobj(cxt
,
1815 "skip update: syscall failed [status=%d]",
1816 cxt
->syscall_status
));
1821 const char *name
= mnt_context_get_writable_tabpath(cxt
);
1823 if (cxt
->action
== MNT_ACT_UMOUNT
&& is_file_empty(name
)) {
1824 DBG(CXT
, ul_debugobj(cxt
,
1825 "skip update: umount, no table"));
1829 cxt
->update
= mnt_new_update();
1833 mnt_update_set_filename(cxt
->update
, name
,
1834 !mnt_context_mtab_writable(cxt
));
1837 if (cxt
->action
== MNT_ACT_UMOUNT
)
1838 rc
= mnt_update_set_fs(cxt
->update
, cxt
->mountflags
,
1839 mnt_context_get_target(cxt
), NULL
);
1841 rc
= mnt_update_set_fs(cxt
->update
, cxt
->mountflags
,
1844 return rc
< 0 ? rc
: 0;
1847 int mnt_context_update_tabs(struct libmnt_context
*cxt
)
1853 if (mnt_context_is_nomtab(cxt
)) {
1854 DBG(CXT
, ul_debugobj(cxt
, "don't update: NOMTAB flag"));
1857 if (!cxt
->update
|| !mnt_update_is_ready(cxt
->update
)) {
1858 DBG(CXT
, ul_debugobj(cxt
, "don't update: no update prepared"));
1862 /* check utab update when external helper executed */
1863 if (mnt_context_helper_executed(cxt
)
1864 && mnt_context_get_helper_status(cxt
) == 0
1865 && mnt_context_utab_writable(cxt
)) {
1867 if (mnt_update_already_done(cxt
->update
, cxt
->lock
)) {
1868 DBG(CXT
, ul_debugobj(cxt
, "don't update: error evaluate or already updated"));
1871 } else if (cxt
->helper
) {
1872 DBG(CXT
, ul_debugobj(cxt
, "don't update: external helper"));
1876 if (cxt
->syscall_status
!= 0
1877 && !(mnt_context_helper_executed(cxt
) &&
1878 mnt_context_get_helper_status(cxt
) == 0)) {
1880 DBG(CXT
, ul_debugobj(cxt
, "don't update: syscall/helper failed/not called"));
1884 fl
= mnt_update_get_mflags(cxt
->update
);
1885 if ((cxt
->mountflags
& MS_RDONLY
) != (fl
& MS_RDONLY
))
1887 * fix MS_RDONLY in options
1889 mnt_update_force_rdonly(cxt
->update
,
1890 cxt
->mountflags
& MS_RDONLY
);
1892 return mnt_update_table(cxt
->update
, cxt
->lock
);
1895 static int apply_table(struct libmnt_context
*cxt
, struct libmnt_table
*tb
,
1898 struct libmnt_fs
*fs
= NULL
;
1899 const char *src
= NULL
, *tgt
= NULL
;
1908 src
= mnt_fs_get_source(cxt
->fs
);
1909 tgt
= mnt_fs_get_target(cxt
->fs
);
1912 fs
= mnt_table_find_pair(tb
, src
, tgt
, direction
);
1915 fs
= mnt_table_find_source(tb
, src
, direction
);
1917 fs
= mnt_table_find_target(tb
, tgt
, direction
);
1919 if (!fs
&& mnt_context_is_swapmatch(cxt
)) {
1920 /* swap source and target (if @src is not LABEL/UUID),
1925 * the path could be a mountpoint as well as a source (for
1926 * example bind mount, symlink to a device, ...).
1928 if (src
&& !mnt_fs_get_tag(cxt
->fs
, NULL
, NULL
))
1929 fs
= mnt_table_find_target(tb
, src
, direction
);
1931 fs
= mnt_table_find_source(tb
, tgt
, direction
);
1936 return -MNT_ERR_NOFSTAB
; /* not found */
1938 DBG(CXT
, ul_debugobj(cxt
, "apply entry:"));
1939 DBG(CXT
, mnt_fs_print_debug(fs
, stderr
));
1941 /* copy from tab to our FS description
1943 rc
= mnt_fs_set_source(cxt
->fs
, mnt_fs_get_source(fs
));
1945 rc
= mnt_fs_set_target(cxt
->fs
, mnt_fs_get_target(fs
));
1947 if (!rc
&& !mnt_fs_get_fstype(cxt
->fs
))
1948 rc
= mnt_fs_set_fstype(cxt
->fs
, mnt_fs_get_fstype(fs
));
1953 if (cxt
->optsmode
& MNT_OMODE_IGNORE
)
1955 else if (cxt
->optsmode
& MNT_OMODE_REPLACE
)
1956 rc
= mnt_fs_set_options(cxt
->fs
, mnt_fs_get_options(fs
));
1958 else if (cxt
->optsmode
& MNT_OMODE_APPEND
)
1959 rc
= mnt_fs_append_options(cxt
->fs
, mnt_fs_get_options(fs
));
1961 else if (cxt
->optsmode
& MNT_OMODE_PREPEND
)
1962 rc
= mnt_fs_prepend_options(cxt
->fs
, mnt_fs_get_options(fs
));
1965 cxt
->flags
|= MNT_FL_TAB_APPLIED
;
1970 * mnt_context_apply_fstab:
1971 * @cxt: mount context
1973 * This function is optional.
1975 * Returns: 0 on success, negative number in case of error.
1977 int mnt_context_apply_fstab(struct libmnt_context
*cxt
)
1980 struct libmnt_table
*tab
= NULL
;
1981 const char *src
= NULL
, *tgt
= NULL
;
1989 if (mnt_context_tab_applied(cxt
)) /* already applied */
1992 if (mnt_context_is_restricted(cxt
)) {
1993 DBG(CXT
, ul_debugobj(cxt
, "force fstab usage for non-root users!"));
1994 cxt
->optsmode
= MNT_OMODE_USER
;
1995 } else if (cxt
->optsmode
== 0) {
1996 DBG(CXT
, ul_debugobj(cxt
, "use default optsmode"));
1997 cxt
->optsmode
= MNT_OMODE_AUTO
;
1998 } else if (cxt
->optsmode
& MNT_OMODE_NOTAB
) {
1999 cxt
->optsmode
&= ~MNT_OMODE_FSTAB
;
2000 cxt
->optsmode
&= ~MNT_OMODE_MTAB
;
2001 cxt
->optsmode
&= ~MNT_OMODE_FORCE
;
2005 src
= mnt_fs_get_source(cxt
->fs
);
2006 tgt
= mnt_fs_get_target(cxt
->fs
);
2009 DBG(CXT
, ul_debugobj(cxt
, "OPTSMODE: ignore=%d, append=%d, prepend=%d, "
2010 "replace=%d, force=%d, fstab=%d, mtab=%d",
2011 cxt
->optsmode
& MNT_OMODE_IGNORE
? 1 : 0,
2012 cxt
->optsmode
& MNT_OMODE_APPEND
? 1 : 0,
2013 cxt
->optsmode
& MNT_OMODE_PREPEND
? 1 : 0,
2014 cxt
->optsmode
& MNT_OMODE_REPLACE
? 1 : 0,
2015 cxt
->optsmode
& MNT_OMODE_FORCE
? 1 : 0,
2016 cxt
->optsmode
& MNT_OMODE_FSTAB
? 1 : 0,
2017 cxt
->optsmode
& MNT_OMODE_MTAB
? 1 : 0));
2019 /* fstab is not required if source and target are specified */
2020 if (src
&& tgt
&& !(cxt
->optsmode
& MNT_OMODE_FORCE
)) {
2021 DBG(CXT
, ul_debugobj(cxt
, "fstab not required -- skip"));
2026 && !(cxt
->optsmode
& MNT_OMODE_FSTAB
)
2027 && !(cxt
->optsmode
& MNT_OMODE_MTAB
)) {
2028 DBG(CXT
, ul_debugobj(cxt
, "only target; fstab/mtab not required "
2029 "-- skip, probably MS_PROPAGATION"));
2033 DBG(CXT
, ul_debugobj(cxt
,
2034 "trying to apply fstab (src=%s, target=%s)", src
, tgt
));
2036 /* let's initialize cxt->fs */
2037 ignore_result( mnt_context_get_fs(cxt
) );
2040 if (cxt
->optsmode
& MNT_OMODE_FSTAB
) {
2041 rc
= mnt_context_get_fstab(cxt
, &tab
);
2043 rc
= apply_table(cxt
, tab
, MNT_ITER_FORWARD
);
2047 if (rc
< 0 && (cxt
->optsmode
& MNT_OMODE_MTAB
)) {
2048 DBG(CXT
, ul_debugobj(cxt
, "trying to apply from mtab"));
2049 rc
= mnt_context_get_mtab(cxt
, &tab
);
2051 rc
= apply_table(cxt
, tab
, MNT_ITER_BACKWARD
);
2054 DBG(CXT
, ul_debugobj(cxt
, "failed to find entry in fstab/mtab"));
2059 * mnt_context_tab_applied:
2060 * @cxt: mount context
2062 * Returns: 1 if fstab (or mtab) has been applied to the context, or 0.
2064 int mnt_context_tab_applied(struct libmnt_context
*cxt
)
2067 return cxt
->flags
& MNT_FL_TAB_APPLIED
;
2071 * This is not a public function!
2073 * Returns 1 if *only propagation flags* change is requested.
2075 int mnt_context_propagation_only(struct libmnt_context
*cxt
)
2080 if (cxt
->action
!= MNT_ACT_MOUNT
)
2083 /* has to be called after context_mount.c: fix_opts() */
2084 assert((cxt
->flags
& MNT_FL_MOUNTOPTS_FIXED
));
2086 /* all propagation mounts are in cxt->addmount */
2087 return !list_empty(&cxt
->addmounts
)
2088 && (cxt
->mountflags
== 0 || cxt
->mountflags
== MS_SILENT
)
2090 && (!cxt
->fs
->fstype
|| strcmp(cxt
->fs
->fstype
, "none") == 0)
2091 && (!cxt
->fs
->source
|| strcmp(cxt
->fs
->source
, "none") == 0);
2095 * mnt_context_get_status:
2096 * @cxt: mount context
2098 * Global libmount status.
2100 * The real exit code of the mount.type helper has to be tested by
2101 * mnt_context_get_helper_status(). The mnt_context_get_status() only informs
2102 * that exec() has been successful.
2104 * Returns: 1 if mount.type or mount(2) syscall has been successfully called.
2106 int mnt_context_get_status(struct libmnt_context
*cxt
)
2109 return !cxt
->syscall_status
|| !cxt
->helper_exec_status
;
2113 * mnt_context_helper_executed:
2114 * @cxt: mount context
2116 * Returns: 1 if mount.type helper has been executed, or 0.
2118 int mnt_context_helper_executed(struct libmnt_context
*cxt
)
2121 return cxt
->helper_exec_status
!= 1;
2125 * mnt_context_get_helper_status:
2126 * @cxt: mount context
2128 * Return: mount.type helper exit status, result is reliable only if
2129 * mnt_context_helper_executed() returns 1.
2131 int mnt_context_get_helper_status(struct libmnt_context
*cxt
)
2134 return cxt
->helper_status
;
2138 * mnt_context_syscall_called:
2139 * @cxt: mount context
2141 * Returns: 1 if mount(2) syscall has been called, or 0.
2143 int mnt_context_syscall_called(struct libmnt_context
*cxt
)
2146 return cxt
->syscall_status
!= 1;
2150 * mnt_context_get_syscall_errno:
2151 * @cxt: mount context
2153 * The result from this function is reliable only if
2154 * mnt_context_syscall_called() returns 1.
2156 * Returns: mount(2) errno if the syscall failed or 0.
2158 int mnt_context_get_syscall_errno(struct libmnt_context
*cxt
)
2161 if (cxt
->syscall_status
< 0)
2162 return -cxt
->syscall_status
;
2167 * mnt_context_set_syscall_status:
2168 * @cxt: mount context
2169 * @status: mount(2) status
2171 * The @status should be 0 on success, or negative number on error (-errno).
2173 * This function should only be used if the [u]mount(2) syscall is NOT called by
2176 * Returns: 0 or negative number in case of error.
2178 int mnt_context_set_syscall_status(struct libmnt_context
*cxt
, int status
)
2184 DBG(CXT
, ul_debugobj(cxt
, "syscall status set to: %d", status
));
2185 cxt
->syscall_status
= status
;
2190 * mnt_context_strerror
2193 * @bufsiz: size of the buffer
2195 * Not implemented yet.
2197 * Returns: 0 or negative number in case of error.
2199 int mnt_context_strerror(struct libmnt_context
*cxt
__attribute__((__unused__
)),
2200 char *buf
__attribute__((__unused__
)),
2201 size_t bufsiz
__attribute__((__unused__
)))
2203 /* TODO: based on cxt->syscall_errno or cxt->helper_status */
2208 * mnt_context_init_helper
2209 * @cxt: mount context
2210 * @action: MNT_ACT_{UMOUNT,MOUNT}
2211 * @flags: not used now
2213 * This function informs libmount that used from [u]mount.type helper.
2215 * The function also calls mnt_context_disable_helpers() to avoid recursive
2216 * mount.type helpers calling. It you really want to call another
2217 * mount.type helper from your helper, then you have to explicitly enable this
2220 * mnt_context_disable_helpers(cxt, FALSE);
2222 * Returns: 0 on success, negative number in case of error.
2224 int mnt_context_init_helper(struct libmnt_context
*cxt
, int action
,
2225 int flags
__attribute__((__unused__
)))
2231 rc
= mnt_context_disable_helpers(cxt
, TRUE
);
2233 rc
= set_flag(cxt
, MNT_FL_HELPER
, 1);
2235 cxt
->action
= action
;
2237 DBG(CXT
, ul_debugobj(cxt
, "initialized for [u]mount.<type> helper [rc=%d]", rc
));
2242 * mnt_context_helper_setopt:
2244 * @c: getopt() result
2245 * @arg: getopt() optarg
2247 * This function applies the [u]mount.type command line option (for example parsed
2248 * by getopt or getopt_long) to @cxt. All unknown options are ignored and
2249 * then 1 is returned.
2251 * Returns: negative number on error, 1 if @c is unknown option, 0 on success.
2253 int mnt_context_helper_setopt(struct libmnt_context
*cxt
, int c
, char *arg
)
2256 switch(cxt
->action
) {
2258 return mnt_context_mount_setopt(cxt
, c
, arg
);
2259 case MNT_ACT_UMOUNT
:
2260 return mnt_context_umount_setopt(cxt
, c
, arg
);
2267 * mnt_context_is_fs_mounted:
2270 * @mounted: returns 1 for mounted and 0 for non-mounted filesystems
2272 * Please, read the mnt_table_is_fs_mounted() description!
2274 * Returns: 0 on success and negative number in case of error.
2276 int mnt_context_is_fs_mounted(struct libmnt_context
*cxt
,
2277 struct libmnt_fs
*fs
, int *mounted
)
2279 struct libmnt_table
*mtab
;
2283 if (!cxt
|| !fs
|| !mounted
)
2286 rc
= mnt_context_get_mtab(cxt
, &mtab
);
2290 *mounted
= mnt_table_is_fs_mounted(mtab
, fs
);
2294 static int mnt_context_add_child(struct libmnt_context
*cxt
, pid_t pid
)
2302 pids
= realloc(cxt
->children
, sizeof(pid_t
) * cxt
->nchildren
+ 1);
2306 DBG(CXT
, ul_debugobj(cxt
, "add new child %d", pid
));
2307 cxt
->children
= pids
;
2308 cxt
->children
[cxt
->nchildren
++] = pid
;
2313 int mnt_fork_context(struct libmnt_context
*cxt
)
2319 if (!mnt_context_is_parent(cxt
))
2322 DBG(CXT
, ul_debugobj(cxt
, "forking context"));
2329 case -1: /* error */
2330 DBG(CXT
, ul_debugobj(cxt
, "fork failed %m"));
2334 cxt
->pid
= getpid();
2335 mnt_context_enable_fork(cxt
, FALSE
);
2336 DBG(CXT
, ul_debugobj(cxt
, "child created"));
2340 rc
= mnt_context_add_child(cxt
, pid
);
2347 int mnt_context_wait_for_children(struct libmnt_context
*cxt
,
2348 int *nchildren
, int *nerrs
)
2356 assert(mnt_context_is_parent(cxt
));
2358 for (i
= 0; i
< cxt
->nchildren
; i
++) {
2359 pid_t pid
= cxt
->children
[i
];
2360 int rc
= 0, ret
= 0;
2365 DBG(CXT
, ul_debugobj(cxt
,
2366 "waiting for child (%d/%d): %d",
2367 i
+ 1, cxt
->nchildren
, pid
));
2369 rc
= waitpid(pid
, &ret
, 0);
2371 } while (rc
== -1 && errno
== EINTR
);
2376 if (rc
!= -1 && nerrs
) {
2378 (*nerrs
) += WEXITSTATUS(ret
) == 0 ? 0 : 1;
2382 cxt
->children
[i
] = 0;
2386 free(cxt
->children
);
2387 cxt
->children
= NULL
;
2395 struct libmnt_lock
*lock
;
2397 static void lock_fallback(void)
2400 mnt_unlock_file(lock
);
2403 int test_mount(struct libmnt_test
*ts
, int argc
, char *argv
[])
2405 int idx
= 1, rc
= 0;
2406 struct libmnt_context
*cxt
;
2411 cxt
= mnt_new_context();
2415 if (!strcmp(argv
[idx
], "-o")) {
2416 mnt_context_set_options(cxt
, argv
[idx
+ 1]);
2419 if (!strcmp(argv
[idx
], "-t")) {
2420 /* TODO: use mnt_context_set_fstype_pattern() */
2421 mnt_context_set_fstype(cxt
, argv
[idx
+ 1]);
2425 if (argc
== idx
+ 1)
2426 /* mount <mountpont>|<device> */
2427 mnt_context_set_target(cxt
, argv
[idx
++]);
2429 else if (argc
== idx
+ 2) {
2430 /* mount <device> <mountpoint> */
2431 mnt_context_set_source(cxt
, argv
[idx
++]);
2432 mnt_context_set_target(cxt
, argv
[idx
++]);
2435 /* this is unnecessary! -- libmount is able to internally
2436 * create and manage the lock
2438 lock
= mnt_context_get_lock(cxt
);
2440 atexit(lock_fallback
);
2442 rc
= mnt_context_mount(cxt
);
2444 warn("failed to mount");
2446 printf("successfully mounted\n");
2448 lock
= NULL
; /* because we use atexit lock_fallback */
2449 mnt_free_context(cxt
);
2453 int test_umount(struct libmnt_test
*ts
, int argc
, char *argv
[])
2455 int idx
= 1, rc
= 0;
2456 struct libmnt_context
*cxt
;
2461 cxt
= mnt_new_context();
2465 if (!strcmp(argv
[idx
], "-t")) {
2466 mnt_context_set_fstype(cxt
, argv
[idx
+ 1]);
2470 if (!strcmp(argv
[idx
], "-f")) {
2471 mnt_context_enable_force(cxt
, TRUE
);
2475 if (!strcmp(argv
[idx
], "-l")) {
2476 mnt_context_enable_lazy(cxt
, TRUE
);
2480 if (!strcmp(argv
[idx
], "-r")) {
2481 mnt_context_enable_rdonly_umount(cxt
, TRUE
);
2485 if (argc
== idx
+ 1) {
2486 /* mount <mountpont>|<device> */
2487 mnt_context_set_target(cxt
, argv
[idx
++]);
2493 lock
= mnt_context_get_lock(cxt
);
2495 atexit(lock_fallback
);
2497 rc
= mnt_context_umount(cxt
);
2499 printf("failed to umount\n");
2501 printf("successfully umounted\n");
2503 lock
= NULL
; /* because we use atexit lock_fallback */
2504 mnt_free_context(cxt
);
2508 int test_flags(struct libmnt_test
*ts
, int argc
, char *argv
[])
2510 int idx
= 1, rc
= 0;
2511 struct libmnt_context
*cxt
;
2512 const char *opt
= NULL
;
2513 unsigned long flags
= 0;
2518 cxt
= mnt_new_context();
2522 if (!strcmp(argv
[idx
], "-o")) {
2523 mnt_context_set_options(cxt
, argv
[idx
+ 1]);
2527 if (argc
== idx
+ 1)
2528 /* mount <mountpont>|<device> */
2529 mnt_context_set_target(cxt
, argv
[idx
++]);
2531 rc
= mnt_context_prepare_mount(cxt
);
2533 printf("failed to prepare mount %s\n", strerror(-rc
));
2535 opt
= mnt_fs_get_options(cxt
->fs
);
2537 fprintf(stdout
, "options: %s\n", opt
);
2539 mnt_context_get_mflags(cxt
, &flags
);
2540 fprintf(stdout
, "flags: %08lx\n", flags
);
2542 mnt_free_context(cxt
);
2546 int test_mountall(struct libmnt_test
*ts
, int argc
, char *argv
[])
2548 struct libmnt_context
*cxt
;
2549 struct libmnt_iter
*itr
;
2550 struct libmnt_fs
*fs
;
2551 int mntrc
, ignored
, idx
= 1;
2553 cxt
= mnt_new_context();
2554 itr
= mnt_new_iter(MNT_ITER_FORWARD
);
2560 if (argv
[idx
] && !strcmp(argv
[idx
], "-O")) {
2561 mnt_context_set_options_pattern(cxt
, argv
[idx
+ 1]);
2564 if (argv
[idx
] && !strcmp(argv
[idx
], "-t")) {
2565 mnt_context_set_fstype_pattern(cxt
, argv
[idx
+ 1]);
2570 while (mnt_context_next_mount(cxt
, itr
, &fs
, &mntrc
, &ignored
) == 0) {
2572 const char *tgt
= mnt_fs_get_target(fs
);
2575 printf("%s: ignored: not match\n", tgt
);
2576 else if (ignored
== 2)
2577 printf("%s: ignored: already mounted\n", tgt
);
2579 else if (!mnt_context_get_status(cxt
)) {
2582 warn("%s: mount failed", tgt
);
2584 warnx("%s: mount failed", tgt
);
2586 printf("%s: successfully mounted\n", tgt
);
2589 mnt_free_context(cxt
);
2593 int main(int argc
, char *argv
[])
2595 struct libmnt_test tss
[] = {
2596 { "--mount", test_mount
, "[-o <opts>] [-t <type>] <spec>|<src> <target>" },
2597 { "--umount", test_umount
, "[-t <type>] [-f][-l][-r] <src>|<target>" },
2598 { "--mount-all", test_mountall
, "[-O <pattern>] [-t <pattern] mount all filesystems from fstab" },
2599 { "--flags", test_flags
, "[-o <opts>] <spec>" },
2602 umask(S_IWGRP
|S_IWOTH
); /* to be compatible with mount(8) */
2604 return mnt_run_test(tss
, argc
, argv
);
2607 #endif /* TEST_PROGRAM */