]>
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
41 * Returns: newly allocated mount context
43 struct libmnt_context
*mnt_new_context(void)
45 struct libmnt_context
*cxt
;
48 cxt
= calloc(1, sizeof(*cxt
));
52 INIT_LIST_HEAD(&cxt
->addmounts
);
57 mnt_context_reset_status(cxt
);
61 /* if we're really root and aren't running setuid */
62 cxt
->restricted
= (uid_t
) 0 == ruid
&& ruid
== euid
? 0 : 1;
64 DBG(CXT
, mnt_debug_h(cxt
, "----> allocate %s",
65 cxt
->restricted
? "[RESTRICTED]" : ""));
67 mnt_has_regular_mtab(&cxt
->mtab_path
, &cxt
->mtab_writable
);
69 if (!cxt
->mtab_writable
)
70 /* use /run/mount/utab if /etc/mtab is useless */
71 mnt_has_regular_utab(&cxt
->utab_path
, &cxt
->utab_writable
);
80 * Deallocates context struct.
82 void mnt_free_context(struct libmnt_context
*cxt
)
87 mnt_reset_context(cxt
);
89 free(cxt
->fstype_pattern
);
90 free(cxt
->optstr_pattern
);
92 if (!(cxt
->flags
& MNT_FL_EXTERN_FSTAB
))
93 mnt_free_table(cxt
->fstab
);
95 mnt_unref_cache(cxt
->cache
);
97 mnt_context_clear_loopdev(cxt
);
98 mnt_free_lock(cxt
->lock
);
99 mnt_free_update(cxt
->update
);
103 DBG(CXT
, mnt_debug_h(cxt
, "<---- free"));
109 * @cxt: mount context
111 * Resets all information in the context that is directly related to
112 * the latest mount (spec, source, target, mount options, ...).
114 * The match patterns, cached fstab, cached canonicalized paths and tags and
115 * [e]uid are not reset. You have to use
117 * mnt_context_set_fstab(cxt, NULL);
118 * mnt_context_set_cache(cxt, NULL);
119 * mnt_context_set_fstype_pattern(cxt, NULL);
120 * mnt_context_set_options_pattern(cxt, NULL);
123 * to reset this stuff.
125 * Returns: 0 on success, negative number in case of error.
127 int mnt_reset_context(struct libmnt_context
*cxt
)
134 DBG(CXT
, mnt_debug_h(cxt
, "<---- reset [status=%d] ---->",
135 mnt_context_get_status(cxt
)));
139 mnt_unref_fs(cxt
->fs
);
140 mnt_free_table(cxt
->mtab
);
143 free(cxt
->orig_user
);
148 cxt
->orig_user
= NULL
;
150 cxt
->user_mountflags
= 0;
151 cxt
->mountdata
= NULL
;
152 cxt
->flags
= MNT_FL_DEFAULT
;
154 /* free additional mounts list */
155 while (!list_empty(&cxt
->addmounts
)) {
156 struct libmnt_addmount
*ad
= list_entry(cxt
->addmounts
.next
,
157 struct libmnt_addmount
,
159 mnt_free_addmount(ad
);
162 mnt_context_reset_status(cxt
);
163 mnt_context_set_tabfilter(cxt
, NULL
, NULL
);
165 /* restore non-resettable flags */
166 cxt
->flags
|= (fl
& MNT_FL_EXTERN_FSTAB
);
167 cxt
->flags
|= (fl
& MNT_FL_EXTERN_CACHE
);
168 cxt
->flags
|= (fl
& MNT_FL_NOMTAB
);
169 cxt
->flags
|= (fl
& MNT_FL_FAKE
);
170 cxt
->flags
|= (fl
& MNT_FL_SLOPPY
);
171 cxt
->flags
|= (fl
& MNT_FL_VERBOSE
);
172 cxt
->flags
|= (fl
& MNT_FL_NOHELPERS
);
173 cxt
->flags
|= (fl
& MNT_FL_LOOPDEL
);
174 cxt
->flags
|= (fl
& MNT_FL_LAZY
);
175 cxt
->flags
|= (fl
& MNT_FL_FORK
);
176 cxt
->flags
|= (fl
& MNT_FL_FORCE
);
177 cxt
->flags
|= (fl
& MNT_FL_NOCANONICALIZE
);
178 cxt
->flags
|= (fl
& MNT_FL_RDONLY_UMOUNT
);
179 cxt
->flags
|= (fl
& MNT_FL_NOSWAPMATCH
);
184 * mnt_context_reset_status:
187 * Resets mount(2) and mount.type statuses, so mnt_context_do_mount() or
188 * mnt_context_do_umount() could be again called with the same settings.
190 * BE CAREFUL -- after this soft reset the libmount will NOT parse mount
191 * options, evaluate permissions or apply stuff from fstab.
193 * Returns: 0 on success, negative number in case of error.
195 int mnt_context_reset_status(struct libmnt_context
*cxt
)
201 cxt
->syscall_status
= 1; /* means not called yet */
202 cxt
->helper_exec_status
= 1;
203 cxt
->helper_status
= 0;
207 static int set_flag(struct libmnt_context
*cxt
, int flag
, int enable
)
213 DBG(CXT
, mnt_debug_h(cxt
, "enabling flag %04x", flag
));
216 DBG(CXT
, mnt_debug_h(cxt
, "disabling flag %04x", flag
));
223 * mnt_context_is_restricted:
224 * @cxt: mount context
226 * Returns: 0 for an unrestricted mount (user is root), or 1 for non-root mounts
228 int mnt_context_is_restricted(struct libmnt_context
*cxt
)
230 return cxt
->restricted
;
234 * mnt_context_set_optsmode
235 * @cxt: mount context
236 * @mode: MNT_OMASK_* flags
238 * Controls how to use mount optionssource and target paths from fstab/mtab.
240 * @MNT_OMODE_IGNORE: ignore mtab/fstab options
242 * @MNT_OMODE_APPEND: append mtab/fstab options to existing options
244 * @MNT_OMODE_PREPEND: prepend mtab/fstab options to existing options
246 * @MNT_OMODE_REPLACE: replace existing options with options from mtab/fstab
248 * @MNT_OMODE_FORCE: always read mtab/fstab (although source and target are defined)
250 * @MNT_OMODE_FSTAB: read from fstab
252 * @MNT_OMODE_MTAB: read from mtab if fstab not enabled or failed
254 * @MNT_OMODE_NOTAB: do not read fstab/mtab at all
256 * @MNT_OMODE_AUTO: default mode (MNT_OMODE_PREPEND | MNT_OMODE_FSTAB | MNT_OMODE_MTAB)
258 * @MNT_OMODE_USER: default for non-root users (MNT_OMODE_REPLACE | MNT_OMODE_FORCE | MNT_OMODE_FSTAB)
262 * - MNT_OMODE_USER is always used if mount context is in restricted mode
263 * - MNT_OMODE_AUTO is used if nothing else is defined
264 * - the flags are evaluated in this order: MNT_OMODE_NOTAB, MNT_OMODE_FORCE,
265 * MNT_OMODE_FSTAB, MNT_OMODE_MTAB and then the mount options from fstab/mtab
266 * are set according to MNT_OMODE_{IGNORE,APPEND,PREPAND,REPLACE}
268 * Returns: 0 on success, negative number in case of error.
270 int mnt_context_set_optsmode(struct libmnt_context
*cxt
, int mode
)
275 cxt
->optsmode
= mode
;
280 * mnt_context_get_optsmode
281 * @cxt: mount context
283 * Returns: MNT_OMASK_* mask or zero.
286 int mnt_context_get_optsmode(struct libmnt_context
*cxt
)
289 return cxt
->optsmode
;
293 * mnt_context_disable_canonicalize:
294 * @cxt: mount context
295 * @disable: TRUE or FALSE
297 * Enable/disable paths canonicalization and tags evaluation. The libmount context
298 * canonicalizes paths when searching in fstab and when preparing source and target paths
299 * for mount(2) syscall.
301 * This fuction has an effect on the private (within context) fstab instance only
302 * (see mnt_context_set_fstab()). If you want to use an external fstab then you
303 * need to manage your private struct libmnt_cache (see mnt_table_set_cache(fstab,
306 * Returns: 0 on success, negative number in case of error.
308 int mnt_context_disable_canonicalize(struct libmnt_context
*cxt
, int disable
)
310 return set_flag(cxt
, MNT_FL_NOCANONICALIZE
, disable
);
314 * mnt_context_is_nocanonicalize:
315 * @cxt: mount context
317 * Returns: 1 if no-canonicalize mode is enabled or 0.
319 int mnt_context_is_nocanonicalize(struct libmnt_context
*cxt
)
321 return cxt
&& (cxt
->flags
& MNT_FL_NOCANONICALIZE
) ? 1 : 0;
325 * mnt_context_enable_lazy:
326 * @cxt: mount context
327 * @enable: TRUE or FALSE
329 * Enable/disable lazy umount (see umount(8) man page, option -l).
331 * Returns: 0 on success, negative number in case of error.
333 int mnt_context_enable_lazy(struct libmnt_context
*cxt
, int enable
)
335 return set_flag(cxt
, MNT_FL_LAZY
, enable
);
339 * mnt_context_is_lazy:
340 * @cxt: mount context
342 * Returns: 1 if lazy umount is enabled or 0
344 int mnt_context_is_lazy(struct libmnt_context
*cxt
)
346 return cxt
->flags
& MNT_FL_LAZY
? 1 : 0;
350 * mnt_context_enable_fork:
351 * @cxt: mount context
352 * @enable: TRUE or FALSE
354 * Enable/disable fork(2) call in mnt_context_next_mount() (see mount(8) man
357 * Returns: 0 on success, negative number in case of error.
359 int mnt_context_enable_fork(struct libmnt_context
*cxt
, int enable
)
361 return set_flag(cxt
, MNT_FL_FORK
, enable
);
365 * mnt_context_is_fork:
366 * @cxt: mount context
368 * Returns: 1 if fork (mount -F) is enabled or 0
370 int mnt_context_is_fork(struct libmnt_context
*cxt
)
372 return cxt
->flags
& MNT_FL_FORK
? 1 : 0;
376 * mnt_context_is_parent:
377 * @cxt: mount context
379 * Return: 1 if mount -F enabled and the current context is parent, or 0
381 int mnt_context_is_parent(struct libmnt_context
*cxt
)
383 return mnt_context_is_fork(cxt
) && cxt
->pid
== 0;
387 * mnt_context_is_child:
388 * @cxt: mount context
390 * Return: 1 if mount -F enabled and the current context is child, or 0
392 int mnt_context_is_child(struct libmnt_context
*cxt
)
394 return !mnt_context_is_fork(cxt
) && cxt
->pid
;
398 * mnt_context_enable_rdonly_umount:
399 * @cxt: mount context
400 * @enable: TRUE or FALSE
402 * Enable/disable read-only remount on failed umount(2)
403 * (see umount(8) man page, option -r).
405 * Returns: 0 on success, negative number in case of error.
407 int mnt_context_enable_rdonly_umount(struct libmnt_context
*cxt
, int enable
)
409 return set_flag(cxt
, MNT_FL_RDONLY_UMOUNT
, enable
);
413 * mnt_context_is_rdonly_umount
414 * @cxt: mount context
416 * See also mnt_context_enable_rdonly_umount() and umount(8) man page,
419 * Returns: 1 if read-only remount failed umount(2) is enables or 0
421 int mnt_context_is_rdonly_umount(struct libmnt_context
*cxt
)
423 return cxt
->flags
& MNT_FL_RDONLY_UMOUNT
? 1 : 0;
427 * mnt_context_disable_helpers:
428 * @cxt: mount context
429 * @disable: TRUE or FALSE
431 * Enable/disable /sbin/[u]mount.* helpers (see mount(8) man page, option -i).
433 * Returns: 0 on success, negative number in case of error.
435 int mnt_context_disable_helpers(struct libmnt_context
*cxt
, int disable
)
437 return set_flag(cxt
, MNT_FL_NOHELPERS
, disable
);
441 * mnt_context_is_nohelpers
442 * @cxt: mount context
444 * Returns: 1 if helpers are disabled (mount -i) or 0
446 int mnt_context_is_nohelpers(struct libmnt_context
*cxt
)
448 return cxt
->flags
& MNT_FL_NOHELPERS
? 1 : 0;
453 * mnt_context_enable_sloppy:
454 * @cxt: mount context
455 * @enable: TRUE or FALSE
457 * Set/unset sloppy mounting (see mount(8) man page, option -s).
459 * Returns: 0 on success, negative number in case of error.
461 int mnt_context_enable_sloppy(struct libmnt_context
*cxt
, int enable
)
463 return set_flag(cxt
, MNT_FL_SLOPPY
, enable
);
467 * mnt_context_is_sloppy:
468 * @cxt: mount context
470 * Returns: 1 if sloppy flag is enabled or 0
472 int mnt_context_is_sloppy(struct libmnt_context
*cxt
)
474 return cxt
->flags
& MNT_FL_SLOPPY
? 1 : 0;
478 * mnt_context_enable_fake:
479 * @cxt: mount context
480 * @enable: TRUE or FALSE
482 * Enable/disable fake mounting (see mount(8) man page, option -f).
484 * Returns: 0 on success, negative number in case of error.
486 int mnt_context_enable_fake(struct libmnt_context
*cxt
, int enable
)
488 return set_flag(cxt
, MNT_FL_FAKE
, enable
);
492 * mnt_context_is_fake:
493 * @cxt: mount context
495 * Returns: 1 if fake flag is enabled or 0
497 int mnt_context_is_fake(struct libmnt_context
*cxt
)
499 return cxt
->flags
& MNT_FL_FAKE
? 1 : 0;
503 * mnt_context_disable_mtab:
504 * @cxt: mount context
505 * @disable: TRUE or FALSE
507 * Disable/enable mtab update (see mount(8) man page, option -n).
509 * Returns: 0 on success, negative number in case of error.
511 int mnt_context_disable_mtab(struct libmnt_context
*cxt
, int disable
)
513 return set_flag(cxt
, MNT_FL_NOMTAB
, disable
);
517 * mnt_context_is_nomtab:
518 * @cxt: mount context
520 * Returns: 1 if no-mtab is enabled or 0
522 int mnt_context_is_nomtab(struct libmnt_context
*cxt
)
524 return cxt
->flags
& MNT_FL_NOMTAB
? 1 : 0;
528 * mnt_context_disable_swapmatch:
529 * @cxt: mount context
530 * @disable: TRUE or FALSE
532 * Disable/enable swap between source and target for mount(8) if only one path
535 * Returns: 0 on success, negative number in case of error.
537 int mnt_context_disable_swapmatch(struct libmnt_context
*cxt
, int disable
)
539 return set_flag(cxt
, MNT_FL_NOSWAPMATCH
, disable
);
543 * mnt_context_is_swapmatch:
544 * @cxt: mount context
546 * Returns: 1 if swap between source and target is allowed (default is 1) or 0.
548 int mnt_context_is_swapmatch(struct libmnt_context
*cxt
)
550 return cxt
->flags
& MNT_FL_NOSWAPMATCH
? 0 : 1;
554 * mnt_context_enable_force:
555 * @cxt: mount context
556 * @enable: TRUE or FALSE
558 * Enable/disable force umounting (see umount(8) man page, option -f).
560 * Returns: 0 on success, negative number in case of error.
562 int mnt_context_enable_force(struct libmnt_context
*cxt
, int enable
)
564 return set_flag(cxt
, MNT_FL_FORCE
, enable
);
568 * mnt_context_is_force
569 * @cxt: mount context
571 * Returns: 1 if force umounting flag is enabled or 0
573 int mnt_context_is_force(struct libmnt_context
*cxt
)
575 return cxt
->flags
& MNT_FL_FORCE
? 1 : 0;
579 * mnt_context_enable_verbose:
580 * @cxt: mount context
581 * @enable: TRUE or FALSE
583 * Enable/disable verbose output (TODO: not implemented yet)
585 * Returns: 0 on success, negative number in case of error.
587 int mnt_context_enable_verbose(struct libmnt_context
*cxt
, int enable
)
589 return set_flag(cxt
, MNT_FL_VERBOSE
, enable
);
593 * mnt_context_is_verbose
594 * @cxt: mount context
596 * Returns: 1 if verbose flag is enabled or 0
598 int mnt_context_is_verbose(struct libmnt_context
*cxt
)
600 return cxt
->flags
& MNT_FL_VERBOSE
? 1 : 0;
604 * mnt_context_enable_loopdel:
605 * @cxt: mount context
606 * @enable: TRUE or FALSE
608 * Enable/disable the loop delete (destroy) after umount (see umount(8), option -d)
610 * Returns: 0 on success, negative number in case of error.
612 int mnt_context_enable_loopdel(struct libmnt_context
*cxt
, int enable
)
614 return set_flag(cxt
, MNT_FL_LOOPDEL
, enable
);
618 * mnt_context_is_loopdel:
619 * @cxt: mount context
621 * Returns: 1 if loop device should be deleted after umount (umount -d) or 0.
623 int mnt_context_is_loopdel(struct libmnt_context
*cxt
)
625 return cxt
->flags
& MNT_FL_LOOPDEL
? 1 : 0;
629 * mnt_context_set_fs:
630 * @cxt: mount context
631 * @fs: filesystem description
633 * The mount context uses private @fs by default. This function allows to
634 * overwrite the private @fs with an external instance. This function
635 * increments @fs reference counter (and deincrement reference counter of the
638 * The @fs will be modified by mnt_context_set_{source,target,options,fstype}
639 * functions, If the @fs is NULL, then all current FS specific settings (source,
640 * target, etc., exclude spec) are reset.
642 * Returns: 0 on success, negative number in case of error.
644 int mnt_context_set_fs(struct libmnt_context
*cxt
, struct libmnt_fs
*fs
)
649 mnt_ref_fs(fs
); /* new */
650 mnt_unref_fs(cxt
->fs
); /* old */
656 * mnt_context_get_fs:
657 * @cxt: mount context
659 * The FS contains the basic description of mountpoint, fs type and so on.
660 * Note that the FS is modified by mnt_context_set_{source,target,options,fstype}
663 * Returns: pointer to FS description or NULL in case of a calloc() error.
665 struct libmnt_fs
*mnt_context_get_fs(struct libmnt_context
*cxt
)
671 cxt
->fs
= mnt_new_fs();
676 * mnt_context_get_fs_userdata:
677 * @cxt: mount context
679 * Returns: pointer to userdata or NULL.
681 void *mnt_context_get_fs_userdata(struct libmnt_context
*cxt
)
684 return cxt
->fs
? mnt_fs_get_userdata(cxt
->fs
) : NULL
;
688 * mnt_context_get_fstab_userdata:
689 * @cxt: mount context
691 * Returns: pointer to userdata or NULL.
693 void *mnt_context_get_fstab_userdata(struct libmnt_context
*cxt
)
696 return cxt
->fstab
? mnt_table_get_userdata(cxt
->fstab
) : NULL
;
700 * mnt_context_get_mtab_userdata:
701 * @cxt: mount context
703 * Returns: pointer to userdata or NULL.
705 void *mnt_context_get_mtab_userdata(struct libmnt_context
*cxt
)
708 return cxt
->mtab
? mnt_table_get_userdata(cxt
->mtab
) : NULL
;
712 * mnt_context_set_source:
713 * @cxt: mount context
714 * @source: mount source (device, directory, UUID, LABEL, ...)
716 * Returns: 0 on success, negative number in case of error.
718 int mnt_context_set_source(struct libmnt_context
*cxt
, const char *source
)
721 return mnt_fs_set_source(mnt_context_get_fs(cxt
), source
);
725 * mnt_context_get_source:
726 * @cxt: mount context
728 * Returns: returns pointer or NULL in case of error or if not set.
730 const char *mnt_context_get_source(struct libmnt_context
*cxt
)
733 return mnt_fs_get_source(mnt_context_get_fs(cxt
));
737 * mnt_context_set_target:
738 * @cxt: mount context
739 * @target: mountpoint
741 * Returns: 0 on success, negative number in case of error.
743 int mnt_context_set_target(struct libmnt_context
*cxt
, const char *target
)
746 return mnt_fs_set_target(mnt_context_get_fs(cxt
), target
);
750 * mnt_context_get_target:
751 * @cxt: mount context
753 * Returns: returns pointer or NULL in case of error or if not set.
755 const char *mnt_context_get_target(struct libmnt_context
*cxt
)
758 return mnt_fs_get_target(mnt_context_get_fs(cxt
));
762 * mnt_context_set_fstype:
763 * @cxt: mount context
764 * @fstype: filesystem type
766 * Note that the @fstype has to be a FS type. For patterns with
767 * comma-separated list of filesystems or for the "nofs" notation, use
768 * mnt_context_set_fstype_pattern().
770 * Returns: 0 on success, negative number in case of error.
772 int mnt_context_set_fstype(struct libmnt_context
*cxt
, const char *fstype
)
775 return mnt_fs_set_fstype(mnt_context_get_fs(cxt
), fstype
);
779 * mnt_context_get_fstype:
780 * @cxt: mount context
782 * Returns: pointer or NULL in case of error or if not set.
784 const char *mnt_context_get_fstype(struct libmnt_context
*cxt
)
787 return mnt_fs_get_fstype(mnt_context_get_fs(cxt
));
791 * mnt_context_set_options:
792 * @cxt: mount context
793 * @optstr: comma delimited mount options
795 * Returns: 0 on success, negative number in case of error.
797 int mnt_context_set_options(struct libmnt_context
*cxt
, const char *optstr
)
800 return mnt_fs_set_options(mnt_context_get_fs(cxt
), optstr
);
804 * mnt_context_append_options:
805 * @cxt: mount context
806 * @optstr: comma delimited mount options
808 * Returns: 0 on success, negative number in case of error.
810 int mnt_context_append_options(struct libmnt_context
*cxt
, const char *optstr
)
813 return mnt_fs_append_options(mnt_context_get_fs(cxt
), optstr
);
817 * mnt_context_get_options:
818 * @cxt: mount context
820 * This function returns mount options set by mnt_context_set_options() or
821 * mnt_context_append_options().
823 * Note that *after* mnt_context_prepare_mount(), the mount options string
824 * may also include options set by mnt_context_set_mflags() or other options
825 * generated by this library.
827 * Returns: pointer or NULL
829 const char *mnt_context_get_options(struct libmnt_context
*cxt
)
832 return mnt_fs_get_options(mnt_context_get_fs(cxt
));
836 * mnt_context_set_fstype_pattern:
837 * @cxt: mount context
838 * @pattern: FS name pattern (or NULL to reset the current setting)
840 * See mount(8), option -t.
842 * Returns: 0 on success, negative number in case of error.
844 int mnt_context_set_fstype_pattern(struct libmnt_context
*cxt
, const char *pattern
)
856 free(cxt
->fstype_pattern
);
857 cxt
->fstype_pattern
= p
;
862 * mnt_context_set_options_pattern:
863 * @cxt: mount context
864 * @pattern: options pattern (or NULL to reset the current setting)
866 * See mount(8), option -O.
868 * Returns: 0 on success, negative number in case of error.
870 int mnt_context_set_options_pattern(struct libmnt_context
*cxt
, const char *pattern
)
882 free(cxt
->optstr_pattern
);
883 cxt
->optstr_pattern
= p
;
888 * mnt_context_set_fstab:
889 * @cxt: mount context
892 * The mount context reads /etc/fstab to the private struct libmnt_table by default.
893 * This function allows to overwrite the private fstab with an external
894 * instance. Note that the external instance is not deallocated by mnt_free_context().
896 * The fstab is used read-only and is not modified, it should be possible to
897 * share the fstab between more mount contexts (TODO: test it.)
899 * If the @tb argument is NULL, then the current private fstab instance is
902 * Returns: 0 on success, negative number in case of error.
904 int mnt_context_set_fstab(struct libmnt_context
*cxt
, struct libmnt_table
*tb
)
909 if (!(cxt
->flags
& MNT_FL_EXTERN_FSTAB
))
910 mnt_free_table(cxt
->fstab
);
912 set_flag(cxt
, MNT_FL_EXTERN_FSTAB
, tb
!= NULL
);
918 * mnt_context_get_fstab:
919 * @cxt: mount context
922 * See also mnt_table_parse_fstab() for more details about fstab.
924 * Returns: 0 on success, negative number in case of error.
926 int mnt_context_get_fstab(struct libmnt_context
*cxt
, struct libmnt_table
**tb
)
934 cxt
->fstab
= mnt_new_table();
937 if (cxt
->table_errcb
)
938 mnt_table_set_parser_errcb(cxt
->fstab
, cxt
->table_errcb
);
939 cxt
->flags
&= ~MNT_FL_EXTERN_FSTAB
;
940 rc
= mnt_table_parse_fstab(cxt
->fstab
, NULL
);
945 /* never touch an external fstab */
946 if (!(cxt
->flags
& MNT_FL_EXTERN_FSTAB
))
947 mnt_table_set_cache(cxt
->fstab
, mnt_context_get_cache(cxt
));
955 * mnt_context_get_mtab:
956 * @cxt: mount context
959 * See also mnt_table_parse_mtab() for more details about mtab/mountinfo. The
960 * result will be deallocated by mnt_free_context(@cxt).
962 * Returns: 0 on success, negative number in case of error.
964 int mnt_context_get_mtab(struct libmnt_context
*cxt
, struct libmnt_table
**tb
)
972 cxt
->mtab
= mnt_new_table();
976 if (cxt
->table_errcb
)
977 mnt_table_set_parser_errcb(cxt
->mtab
, cxt
->table_errcb
);
978 if (cxt
->table_fltrcb
)
979 mnt_table_set_parser_fltrcb(cxt
->mtab
,
981 cxt
->table_fltrcb_data
);
983 rc
= mnt_table_parse_mtab(cxt
->mtab
, cxt
->mtab_path
);
988 mnt_table_set_cache(cxt
->mtab
, mnt_context_get_cache(cxt
));
993 DBG(CXT
, mnt_debug_h(cxt
, "mtab requested [nents=%d]",
994 mnt_table_get_nents(cxt
->mtab
)));
999 * Allows to specify a filter for tab file entries. The filter is called by
1000 * the table parser. Currently used for mtab and utab only.
1002 int mnt_context_set_tabfilter(struct libmnt_context
*cxt
,
1003 int (*fltr
)(struct libmnt_fs
*, void *),
1010 cxt
->table_fltrcb
= fltr
;
1011 cxt
->table_fltrcb_data
= data
;
1014 mnt_table_set_parser_fltrcb(cxt
->mtab
,
1016 cxt
->table_fltrcb_data
);
1018 DBG(CXT
, mnt_debug_h(cxt
, "tabfiler %s", fltr
? "ENABLED!" : "disabled"));
1023 * mnt_context_get_table:
1024 * @cxt: mount context
1025 * @filename: e.g. /proc/self/mountinfo
1026 * @tb: returns the table
1028 * This function allocates a new table and parses the @file. The parser error
1029 * callback and cache for tags and paths is set according to the @cxt setting.
1030 * See also mnt_table_parse_file().
1032 * It's strongly recommended to use the mnt_context_get_mtab() and
1033 * mnt_context_get_fstab() functions for mtab and fstab files. This function
1034 * does not care about LIBMOUNT_* env.variables and does not merge userspace
1037 * The result will NOT be deallocated by mnt_free_context(@cxt).
1039 * Returns: 0 on success, negative number in case of error.
1041 int mnt_context_get_table(struct libmnt_context
*cxt
,
1042 const char *filename
, struct libmnt_table
**tb
)
1051 *tb
= mnt_new_table();
1055 if (cxt
->table_errcb
)
1056 mnt_table_set_parser_errcb(*tb
, cxt
->table_errcb
);
1058 rc
= mnt_table_parse_file(*tb
, filename
);
1060 mnt_free_table(*tb
);
1064 mnt_table_set_cache(*tb
, mnt_context_get_cache(cxt
));
1069 * mnt_context_set_tables_errcb
1070 * @cxt: mount context
1071 * @cb: pointer to callback function
1073 * The error callback is used for all tab files (e.g. mtab, fstab)
1074 * parsed within the context.
1076 * See also mnt_context_get_mtab(),
1077 * mnt_context_get_fstab(),
1078 * mnt_table_set_parser_errcb().
1080 * Returns: 0 on success, negative number in case of error.
1082 int mnt_context_set_tables_errcb(struct libmnt_context
*cxt
,
1083 int (*cb
)(struct libmnt_table
*tb
, const char *filename
, int line
))
1089 cxt
->table_errcb
= cb
;
1094 * mnt_context_set_cache:
1095 * @cxt: mount context
1096 * @cache: cache instance or nULL
1098 * The mount context maintains a private struct libmnt_cache by default. This
1099 * function allows to overwrite the private cache with an external instance.
1100 * This function increments cache reference counter.
1102 * If the @cache argument is NULL, then the current private cache instance is
1105 * The old cache instance reference counter is de-incremented.
1107 * Returns: 0 on success, negative number in case of error.
1109 int mnt_context_set_cache(struct libmnt_context
*cxt
, struct libmnt_cache
*cache
)
1114 mnt_ref_cache(cache
); /* new */
1115 mnt_unref_cache(cxt
->cache
); /* old */
1122 * mnt_context_get_cache
1123 * @cxt: mount context
1125 * See also mnt_context_set_cache().
1127 * Returns: pointer to cache or NULL if canonicalization is disabled.
1129 struct libmnt_cache
*mnt_context_get_cache(struct libmnt_context
*cxt
)
1132 if (!cxt
|| mnt_context_is_nocanonicalize(cxt
))
1136 cxt
->cache
= mnt_new_cache();
1144 * mnt_context_set_passwd_cb:
1145 * @cxt: mount context
1146 * @get: callback to get password
1147 * @release: callback to release (delallocate) password
1149 * Sets callbacks for encryption password (e.g encrypted loopdev). This
1150 * function is deprecated (encrypted loops are no longer supported).
1152 * Returns: 0 on success, negative number in case of error.
1154 int mnt_context_set_passwd_cb(struct libmnt_context
*cxt
,
1155 char *(*get
)(struct libmnt_context
*),
1156 void (*release
)(struct libmnt_context
*, char *))
1161 cxt
->pwd_get_cb
= get
;
1162 cxt
->pwd_release_cb
= release
;
1167 * mnt_context_get_lock:
1168 * @cxt: mount context
1170 * The libmount applications don't have to care about mtab locking, but with a
1171 * small exception: the application has to be able to remove the lock file when
1172 * interrupted by signal or signals have to be ignored when the lock is locked.
1174 * The default behavior is to ignore all signals (except SIGALRM and
1175 * SIGTRAP for mtab udate) when the lock is locked. If this behavior
1176 * is unacceptable, then use:
1178 * lc = mnt_context_get_lock(cxt);
1180 * mnt_lock_block_signals(lc, FALSE);
1182 * and don't forget to call mnt_unlock_file(lc) before exit.
1184 * Returns: pointer to lock struct or NULL.
1186 struct libmnt_lock
*mnt_context_get_lock(struct libmnt_context
*cxt
)
1190 * DON'T call this function within libmount, it will always allocate
1191 * the lock. The mnt_update_* functions are able to allocate the lock
1192 * only when mtab/utab update is really necessary.
1194 if (!cxt
|| mnt_context_is_nomtab(cxt
))
1198 cxt
->lock
= mnt_new_lock(cxt
->mtab_writable
?
1199 cxt
->mtab_path
: cxt
->utab_path
, 0);
1201 mnt_lock_block_signals(cxt
->lock
, TRUE
);
1207 * mnt_context_set_mflags:
1208 * @cxt: mount context
1209 * @flags: mount(2) flags (MS_* flags)
1211 * Sets mount flags (see mount(2) man page).
1213 * Note that mount context allows to define mount options by mount flags. It
1214 * means you can for example use
1216 * mnt_context_set_mflags(cxt, MS_NOEXEC | MS_NOSUID);
1220 * mnt_context_set_options(cxt, "noexec,nosuid");
1222 * both of these calls have the same effect.
1224 * Returns: 0 on success, negative number in case of error.
1226 int mnt_context_set_mflags(struct libmnt_context
*cxt
, unsigned long flags
)
1232 cxt
->mountflags
= flags
;
1234 if ((cxt
->flags
& MNT_FL_MOUNTOPTS_FIXED
) && cxt
->fs
)
1236 * the final mount options are already generated, refresh...
1238 return mnt_optstr_apply_flags(
1239 &cxt
->fs
->vfs_optstr
,
1241 mnt_get_builtin_optmap(MNT_LINUX_MAP
));
1247 * mnt_context_get_mflags:
1248 * @cxt: mount context
1249 * @flags: returns MS_* mount flags
1251 * Converts mount options string to MS_* flags and bitewise-OR the result with
1252 * the already defined flags (see mnt_context_set_mflags()).
1254 * Returns: 0 on success, negative number in case of error.
1256 int mnt_context_get_mflags(struct libmnt_context
*cxt
, unsigned long *flags
)
1259 struct list_head
*p
;
1267 if (!(cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
) && cxt
->fs
) {
1268 const char *o
= mnt_fs_get_options(cxt
->fs
);
1270 rc
= mnt_optstr_get_flags(o
, flags
,
1271 mnt_get_builtin_optmap(MNT_LINUX_MAP
));
1274 list_for_each(p
, &cxt
->addmounts
) {
1275 struct libmnt_addmount
*ad
=
1276 list_entry(p
, struct libmnt_addmount
, mounts
);
1278 *flags
|= ad
->mountflags
;
1282 *flags
|= cxt
->mountflags
;
1287 * mnt_context_set_user_mflags:
1288 * @cxt: mount context
1289 * @flags: mount(2) flags (MNT_MS_* flags, e.g. MNT_MS_LOOP)
1291 * Sets userspace mount flags.
1293 * See also notes for mnt_context_set_mflags().
1295 * Returns: 0 on success, negative number in case of error.
1297 int mnt_context_set_user_mflags(struct libmnt_context
*cxt
, unsigned long flags
)
1302 cxt
->user_mountflags
= flags
;
1307 * mnt_context_get_user_mflags:
1308 * @cxt: mount context
1309 * @flags: returns mount flags
1311 * Converts mount options string to MNT_MS_* flags and bitewise-OR the result
1312 * with the already defined flags (see mnt_context_set_user_mflags()).
1314 * Returns: 0 on success, negative number in case of error.
1316 int mnt_context_get_user_mflags(struct libmnt_context
*cxt
, unsigned long *flags
)
1326 if (!(cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
) && cxt
->fs
) {
1327 const char *o
= mnt_fs_get_user_options(cxt
->fs
);
1329 rc
= mnt_optstr_get_flags(o
, flags
,
1330 mnt_get_builtin_optmap(MNT_USERSPACE_MAP
));
1333 *flags
|= cxt
->user_mountflags
;
1338 * mnt_context_set_mountdata:
1339 * @cxt: mount context
1340 * @data: mount(2) data
1342 * The mount context generates mountdata from mount options by default. This
1343 * function allows to overwrite this behavior, and @data will be used instead
1346 * The libmount does not deallocate the data by mnt_free_context(). Note that
1347 * NULL is also valid mount data.
1349 * Returns: 0 on success, negative number in case of error.
1351 int mnt_context_set_mountdata(struct libmnt_context
*cxt
, void *data
)
1356 cxt
->mountdata
= data
;
1357 cxt
->flags
|= MNT_FL_MOUNTDATA
;
1362 * Translates LABEL/UUID/path to mountable path
1364 int mnt_context_prepare_srcpath(struct libmnt_context
*cxt
)
1366 const char *path
= NULL
;
1367 struct libmnt_cache
*cache
;
1368 const char *t
, *v
, *src
;
1373 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
1375 if (!cxt
|| !cxt
->fs
)
1378 DBG(CXT
, mnt_debug_h(cxt
, "preparing source path"));
1380 src
= mnt_fs_get_source(cxt
->fs
);
1382 if (!src
&& mnt_context_propagation_only(cxt
))
1383 /* mount --make-{shared,private,...} */
1384 return mnt_fs_set_source(cxt
->fs
, "none");
1386 /* ignore filesystems without source or filesystems
1387 * where the source is a quasi-path (//foo/bar)
1389 if (!src
|| mnt_fs_is_netfs(cxt
->fs
))
1392 DBG(CXT
, mnt_debug_h(cxt
, "srcpath '%s'", src
));
1394 cache
= mnt_context_get_cache(cxt
);
1396 if (!mnt_fs_get_tag(cxt
->fs
, &t
, &v
)) {
1398 * Source is TAG (evaluate)
1401 path
= mnt_resolve_tag(t
, v
, cache
);
1403 rc
= path
? mnt_fs_set_source(cxt
->fs
, path
) : -MNT_ERR_NOSOURCE
;
1405 } else if (cache
&& !mnt_fs_is_pseudofs(cxt
->fs
)) {
1407 * Source is PATH (canonicalize)
1409 path
= mnt_resolve_path(src
, cache
);
1410 if (path
&& strcmp(path
, src
))
1411 rc
= mnt_fs_set_source(cxt
->fs
, path
);
1415 DBG(CXT
, mnt_debug_h(cxt
, "failed to prepare srcpath [rc=%d]", rc
));
1422 if ((cxt
->mountflags
& (MS_BIND
| MS_MOVE
| MS_REMOUNT
))
1423 || mnt_fs_is_pseudofs(cxt
->fs
)) {
1424 DBG(CXT
, mnt_debug_h(cxt
, "REMOUNT/BIND/MOVE/pseudo FS source: %s", path
));
1429 * Initialize loop device
1431 if (mnt_context_is_loopdev(cxt
)) {
1432 rc
= mnt_context_setup_loopdev(cxt
);
1437 DBG(CXT
, mnt_debug_h(cxt
, "final srcpath '%s'",
1438 mnt_fs_get_source(cxt
->fs
)));
1442 /* create a mountpoint if x-mount.mkdir[=<mode>] specified */
1443 static int mkdir_target(const char *tgt
, struct libmnt_fs
*fs
)
1454 if (mnt_optstr_get_option(fs
->user_optstr
, "x-mount.mkdir", &mstr
, &mstr_sz
) != 0)
1456 if (stat(tgt
, &st
) == 0)
1459 if (mstr
&& mstr_sz
) {
1463 mode
= strtol(mstr
, &end
, 8);
1465 if (errno
|| !end
|| mstr
+ mstr_sz
!= end
) {
1466 DBG(CXT
, mnt_debug("failed to parse mkdir mode '%s'", mstr
));
1467 return -MNT_ERR_MOUNTOPT
;
1472 mode
= S_IRWXU
| /* 0755 */
1476 rc
= mkdir_p(tgt
, mode
);
1478 DBG(CXT
, mnt_debug("mkdir %s failed: %m", tgt
));
1483 int mnt_context_prepare_target(struct libmnt_context
*cxt
)
1486 struct libmnt_cache
*cache
;
1491 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
1493 if (!cxt
|| !cxt
->fs
)
1496 DBG(CXT
, mnt_debug_h(cxt
, "preparing target path"));
1498 tgt
= mnt_fs_get_target(cxt
->fs
);
1503 if (cxt
->action
== MNT_ACT_MOUNT
1504 && !mnt_context_is_restricted(cxt
)
1505 && cxt
->user_mountflags
& MNT_MS_XCOMMENT
) {
1507 rc
= mkdir_target(tgt
, cxt
->fs
);
1509 return rc
; /* mkdir or parse error */
1512 /* canonicalize the path */
1513 cache
= mnt_context_get_cache(cxt
);
1515 char *path
= mnt_resolve_path(tgt
, cache
);
1516 if (path
&& strcmp(path
, tgt
) != 0)
1517 rc
= mnt_fs_set_target(cxt
->fs
, path
);
1521 DBG(CXT
, mnt_debug_h(cxt
, "failed to prepare target '%s'", tgt
));
1523 DBG(CXT
, mnt_debug_h(cxt
, "final target '%s'",
1524 mnt_fs_get_target(cxt
->fs
)));
1529 * It's usually no error when we're not able to detect the filesystem type -- we
1530 * will try to use the types from /{etc,proc}/filesystems.
1532 int mnt_context_guess_fstype(struct libmnt_context
*cxt
)
1540 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
1542 if (!cxt
|| !cxt
->fs
)
1545 if ((cxt
->mountflags
& (MS_BIND
| MS_MOVE
))
1546 || mnt_context_propagation_only(cxt
))
1549 type
= (char *) mnt_fs_get_fstype(cxt
->fs
);
1550 if (type
&& !strcmp(type
, "auto")) {
1551 mnt_fs_set_fstype(cxt
->fs
, NULL
);
1557 if (cxt
->flags
& MS_REMOUNT
)
1559 if (cxt
->fstype_pattern
)
1562 dev
= mnt_fs_get_srcpath(cxt
->fs
);
1566 if (access(dev
, F_OK
) == 0) {
1567 struct libmnt_cache
*cache
= mnt_context_get_cache(cxt
);
1570 type
= mnt_get_fstype(dev
, &ambi
, cache
);
1572 rc
= mnt_fs_set_fstype(cxt
->fs
, type
);
1574 free(type
); /* type is not cached */
1577 rc
= -MNT_ERR_AMBIFS
;
1579 DBG(CXT
, mnt_debug_h(cxt
, "access(%s) failed [%m]", dev
));
1580 if (strchr(dev
, ':') != NULL
)
1581 rc
= mnt_fs_set_fstype(cxt
->fs
, "nfs");
1582 else if (!strncmp(dev
, "//", 2))
1583 rc
= mnt_fs_set_fstype(cxt
->fs
, "cifs");
1587 DBG(CXT
, mnt_debug_h(cxt
, "FS type: %s [rc=%d]",
1588 mnt_fs_get_fstype(cxt
->fs
), rc
));
1591 return mnt_fs_set_fstype(cxt
->fs
, "none");
1595 * The default is to use fstype from cxt->fs, this could be overwritten by
1596 * @type. The @act is MNT_ACT_{MOUNT,UMOUNT}.
1598 * Returns: 0 on success or negative number in case of error. Note that success
1599 * does not mean that there is any usable helper, you have to check cxt->helper.
1601 int mnt_context_prepare_helper(struct libmnt_context
*cxt
, const char *name
,
1604 char search_path
[] = FS_SEARCH_PATH
; /* from config.h */
1605 char *p
= NULL
, *path
;
1609 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
1612 type
= mnt_fs_get_fstype(cxt
->fs
);
1614 if (type
&& strchr(type
, ','))
1615 return 0; /* type is fstype pattern */
1617 if (mnt_context_is_nohelpers(cxt
)
1619 || !strcmp(type
, "none")
1620 || mnt_fs_is_swaparea(cxt
->fs
))
1623 path
= strtok_r(search_path
, ":", &p
);
1625 char helper
[PATH_MAX
];
1629 rc
= snprintf(helper
, sizeof(helper
), "%s/%s.%s",
1631 path
= strtok_r(NULL
, ":", &p
);
1633 if (rc
< 0 || (size_t) rc
>= sizeof(helper
))
1636 rc
= stat(helper
, &st
);
1637 if (rc
== -1 && errno
== ENOENT
&& strchr(type
, '.')) {
1638 /* If type ends with ".subtype" try without it */
1639 char *hs
= strrchr(helper
, '.');
1642 rc
= stat(helper
, &st
);
1645 DBG(CXT
, mnt_debug_h(cxt
, "%-25s ... %s", helper
,
1646 rc
? "not found" : "found"));
1651 cxt
->helper
= strdup(helper
);
1660 int mnt_context_merge_mflags(struct libmnt_context
*cxt
)
1662 unsigned long fl
= 0;
1667 DBG(CXT
, mnt_debug_h(cxt
, "merging mount flags"));
1669 rc
= mnt_context_get_mflags(cxt
, &fl
);
1672 cxt
->mountflags
= fl
;
1675 rc
= mnt_context_get_user_mflags(cxt
, &fl
);
1678 cxt
->user_mountflags
= fl
;
1680 DBG(CXT
, mnt_debug_h(cxt
, "final flags: VFS=%08lx user=%08lx",
1681 cxt
->mountflags
, cxt
->user_mountflags
));
1683 cxt
->flags
|= MNT_FL_MOUNTFLAGS_MERGED
;
1688 * Prepare /etc/mtab or /run/mount/utab
1690 int mnt_context_prepare_update(struct libmnt_context
*cxt
)
1697 assert(cxt
->action
);
1698 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
1700 DBG(CXT
, mnt_debug_h(cxt
, "prepare update"));
1702 if (mnt_context_propagation_only(cxt
)) {
1703 DBG(CXT
, mnt_debug_h(cxt
, "skip update: only MS_PROPAGATION"));
1707 target
= mnt_fs_get_target(cxt
->fs
);
1709 if (cxt
->action
== MNT_ACT_UMOUNT
&& target
&& !strcmp(target
, "/"))
1710 /* Don't try to touch mtab if umounting root FS */
1711 mnt_context_disable_mtab(cxt
, TRUE
);
1713 if (mnt_context_is_nomtab(cxt
)) {
1714 DBG(CXT
, mnt_debug_h(cxt
, "skip update: NOMTAB flag"));
1718 DBG(CXT
, mnt_debug_h(cxt
, "skip update: external helper"));
1721 if (!cxt
->mtab_writable
&& !cxt
->utab_writable
) {
1722 DBG(CXT
, mnt_debug_h(cxt
, "skip update: no writable destination"));
1725 /* 0 = success, 1 = not called yet */
1726 if (cxt
->syscall_status
!= 1 && cxt
->syscall_status
!= 0) {
1727 DBG(CXT
, mnt_debug_h(cxt
,
1728 "skip update: syscall failed [status=%d]",
1729 cxt
->syscall_status
));
1734 const char *name
= cxt
->mtab_writable
? cxt
->mtab_path
: cxt
->utab_path
;
1736 if (cxt
->action
== MNT_ACT_UMOUNT
&& is_file_empty(name
)) {
1737 DBG(CXT
, mnt_debug_h(cxt
,
1738 "skip update: umount, no table"));
1742 cxt
->update
= mnt_new_update();
1746 mnt_update_set_filename(cxt
->update
, name
, !cxt
->mtab_writable
);
1749 if (cxt
->action
== MNT_ACT_UMOUNT
)
1750 rc
= mnt_update_set_fs(cxt
->update
, cxt
->mountflags
,
1751 mnt_context_get_target(cxt
), NULL
);
1753 rc
= mnt_update_set_fs(cxt
->update
, cxt
->mountflags
,
1756 return rc
< 0 ? rc
: 0;
1759 int mnt_context_update_tabs(struct libmnt_context
*cxt
)
1765 if (mnt_context_is_nomtab(cxt
)) {
1766 DBG(CXT
, mnt_debug_h(cxt
, "don't update: NOMTAB flag"));
1770 DBG(CXT
, mnt_debug_h(cxt
, "don't update: external helper"));
1773 if (!cxt
->update
|| !mnt_update_is_ready(cxt
->update
)) {
1774 DBG(CXT
, mnt_debug_h(cxt
, "don't update: no update prepared"));
1777 if (cxt
->syscall_status
) {
1778 DBG(CXT
, mnt_debug_h(cxt
, "don't update: syscall failed/not called"));
1782 fl
= mnt_update_get_mflags(cxt
->update
);
1783 if ((cxt
->mountflags
& MS_RDONLY
) != (fl
& MS_RDONLY
))
1785 * fix MS_RDONLY in options
1787 mnt_update_force_rdonly(cxt
->update
,
1788 cxt
->mountflags
& MS_RDONLY
);
1790 return mnt_update_table(cxt
->update
, cxt
->lock
);
1793 static int apply_table(struct libmnt_context
*cxt
, struct libmnt_table
*tb
,
1796 struct libmnt_fs
*fs
= NULL
;
1797 const char *src
= NULL
, *tgt
= NULL
;
1806 src
= mnt_fs_get_source(cxt
->fs
);
1807 tgt
= mnt_fs_get_target(cxt
->fs
);
1810 fs
= mnt_table_find_pair(tb
, src
, tgt
, direction
);
1813 fs
= mnt_table_find_source(tb
, src
, direction
);
1815 fs
= mnt_table_find_target(tb
, tgt
, direction
);
1817 if (!fs
&& mnt_context_is_swapmatch(cxt
)) {
1818 /* swap source and target (if @src is not LABEL/UUID),
1823 * the path could be a mountpoint as well as a source (for
1824 * example bind mount, symlink to a device, ...).
1826 if (src
&& !mnt_fs_get_tag(cxt
->fs
, NULL
, NULL
))
1827 fs
= mnt_table_find_target(tb
, src
, direction
);
1829 fs
= mnt_table_find_source(tb
, tgt
, direction
);
1834 return -MNT_ERR_NOFSTAB
; /* not found */
1836 DBG(CXT
, mnt_debug_h(cxt
, "apply entry:"));
1837 DBG(CXT
, mnt_fs_print_debug(fs
, stderr
));
1839 /* copy from tab to our FS description
1841 rc
= mnt_fs_set_source(cxt
->fs
, mnt_fs_get_source(fs
));
1843 rc
= mnt_fs_set_target(cxt
->fs
, mnt_fs_get_target(fs
));
1845 if (!rc
&& !mnt_fs_get_fstype(cxt
->fs
))
1846 rc
= mnt_fs_set_fstype(cxt
->fs
, mnt_fs_get_fstype(fs
));
1851 if (cxt
->optsmode
& MNT_OMODE_IGNORE
)
1853 else if (cxt
->optsmode
& MNT_OMODE_REPLACE
)
1854 rc
= mnt_fs_set_options(cxt
->fs
, mnt_fs_get_options(fs
));
1856 else if (cxt
->optsmode
& MNT_OMODE_APPEND
)
1857 rc
= mnt_fs_append_options(cxt
->fs
, mnt_fs_get_options(fs
));
1859 else if (cxt
->optsmode
& MNT_OMODE_PREPEND
)
1860 rc
= mnt_fs_prepend_options(cxt
->fs
, mnt_fs_get_options(fs
));
1863 cxt
->flags
|= MNT_FL_TAB_APPLIED
;
1868 * mnt_context_apply_fstab:
1869 * @cxt: mount context
1871 * This function is optional.
1873 * Returns: 0 on success, negative number in case of error.
1875 int mnt_context_apply_fstab(struct libmnt_context
*cxt
)
1878 struct libmnt_table
*tab
= NULL
;
1879 const char *src
= NULL
, *tgt
= NULL
;
1887 if (mnt_context_tab_applied(cxt
)) /* already applied */
1890 if (mnt_context_is_restricted(cxt
)) {
1891 DBG(CXT
, mnt_debug_h(cxt
, "force fstab usage for non-root users!"));
1892 cxt
->optsmode
= MNT_OMODE_USER
;
1893 } else if (cxt
->optsmode
== 0) {
1894 DBG(CXT
, mnt_debug_h(cxt
, "use default optsmode"));
1895 cxt
->optsmode
= MNT_OMODE_AUTO
;
1896 } else if (cxt
->optsmode
& MNT_OMODE_NOTAB
) {
1897 cxt
->optsmode
&= ~MNT_OMODE_FSTAB
;
1898 cxt
->optsmode
&= ~MNT_OMODE_MTAB
;
1899 cxt
->optsmode
&= ~MNT_OMODE_FORCE
;
1903 src
= mnt_fs_get_source(cxt
->fs
);
1904 tgt
= mnt_fs_get_target(cxt
->fs
);
1907 DBG(CXT
, mnt_debug_h(cxt
, "OPTSMODE: ignore=%d, append=%d, prepend=%d, "
1908 "replace=%d, force=%d, fstab=%d, mtab=%d",
1909 cxt
->optsmode
& MNT_OMODE_IGNORE
? 1 : 0,
1910 cxt
->optsmode
& MNT_OMODE_APPEND
? 1 : 0,
1911 cxt
->optsmode
& MNT_OMODE_PREPEND
? 1 : 0,
1912 cxt
->optsmode
& MNT_OMODE_REPLACE
? 1 : 0,
1913 cxt
->optsmode
& MNT_OMODE_FORCE
? 1 : 0,
1914 cxt
->optsmode
& MNT_OMODE_FSTAB
? 1 : 0,
1915 cxt
->optsmode
& MNT_OMODE_MTAB
? 1 : 0));
1917 /* fstab is not required if source and target are specified */
1918 if (src
&& tgt
&& !(cxt
->optsmode
& MNT_OMODE_FORCE
)) {
1919 DBG(CXT
, mnt_debug_h(cxt
, "fstab not required -- skip"));
1924 && !(cxt
->optsmode
& MNT_OMODE_FSTAB
)
1925 && !(cxt
->optsmode
& MNT_OMODE_MTAB
)) {
1926 DBG(CXT
, mnt_debug_h(cxt
, "only target; fstab/mtab not required "
1927 "-- skip, probably MS_PROPAGATION"));
1931 DBG(CXT
, mnt_debug_h(cxt
,
1932 "trying to apply fstab (src=%s, target=%s)", src
, tgt
));
1934 /* let's initialize cxt->fs */
1935 ignore_result( mnt_context_get_fs(cxt
) );
1938 if (cxt
->optsmode
& MNT_OMODE_FSTAB
) {
1939 rc
= mnt_context_get_fstab(cxt
, &tab
);
1941 rc
= apply_table(cxt
, tab
, MNT_ITER_FORWARD
);
1945 if (rc
< 0 && (cxt
->optsmode
& MNT_OMODE_MTAB
)) {
1946 DBG(CXT
, mnt_debug_h(cxt
, "trying to apply from mtab"));
1947 rc
= mnt_context_get_mtab(cxt
, &tab
);
1949 rc
= apply_table(cxt
, tab
, MNT_ITER_BACKWARD
);
1952 DBG(CXT
, mnt_debug_h(cxt
, "failed to find entry in fstab/mtab"));
1957 * mnt_context_tab_applied:
1958 * @cxt: mount context
1960 * Returns: 1 if fstab (or mtab) has been applied to the context, or 0.
1962 int mnt_context_tab_applied(struct libmnt_context
*cxt
)
1965 return cxt
->flags
& MNT_FL_TAB_APPLIED
;
1969 * This is not a public function!
1971 * Returns 1 if *only propagation flags* change is requested.
1973 int mnt_context_propagation_only(struct libmnt_context
*cxt
)
1978 if (cxt
->action
!= MNT_ACT_MOUNT
)
1981 /* has to be called after context_mount.c: fix_opts() */
1982 assert((cxt
->flags
& MNT_FL_MOUNTOPTS_FIXED
));
1984 /* all propagation mounts are in cxt->addmount */
1985 return !list_empty(&cxt
->addmounts
)
1986 && (cxt
->mountflags
== 0 || cxt
->mountflags
== MS_SILENT
)
1988 && (!cxt
->fs
->fstype
|| strcmp(cxt
->fs
->fstype
, "none") == 0)
1989 && (!cxt
->fs
->source
|| strcmp(cxt
->fs
->source
, "none") == 0);
1993 * mnt_context_get_status:
1994 * @cxt: mount context
1996 * Global libmount status.
1998 * The real exit code of the mount.type helper has to be tested by
1999 * mnt_context_get_helper_status(). The mnt_context_get_status() only informs
2000 * that exec() has been successful.
2002 * Returns: 1 if mount.type or mount(2) syscall has been successfully called.
2004 int mnt_context_get_status(struct libmnt_context
*cxt
)
2007 return !cxt
->syscall_status
|| !cxt
->helper_exec_status
;
2011 * mnt_context_helper_executed:
2012 * @cxt: mount context
2014 * Returns: 1 if mount.type helper has been executed, or 0.
2016 int mnt_context_helper_executed(struct libmnt_context
*cxt
)
2019 return cxt
->helper_exec_status
!= 1;
2023 * mnt_context_get_helper_status:
2024 * @cxt: mount context
2026 * Return: mount.type helper exit status, result is reliable only if
2027 * mnt_context_helper_executed() returns 1.
2029 int mnt_context_get_helper_status(struct libmnt_context
*cxt
)
2032 return cxt
->helper_status
;
2036 * mnt_context_syscall_called:
2037 * @cxt: mount context
2039 * Returns: 1 if mount(2) syscall has been called, or 0.
2041 int mnt_context_syscall_called(struct libmnt_context
*cxt
)
2044 return cxt
->syscall_status
!= 1;
2048 * mnt_context_get_syscall_errno:
2049 * @cxt: mount context
2051 * The result from this function is reliable only if
2052 * mnt_context_syscall_called() returns 1.
2054 * Returns: mount(2) errno if the syscall failed or 0.
2056 int mnt_context_get_syscall_errno(struct libmnt_context
*cxt
)
2059 if (cxt
->syscall_status
< 0)
2060 return -cxt
->syscall_status
;
2065 * mnt_context_set_syscall_status:
2066 * @cxt: mount context
2067 * @status: mount(2) status
2069 * The @status should be 0 on success, or negative number on error (-errno).
2071 * This function should only be used if the [u]mount(2) syscall is NOT called by
2074 * Returns: 0 or negative number in case of error.
2076 int mnt_context_set_syscall_status(struct libmnt_context
*cxt
, int status
)
2082 DBG(CXT
, mnt_debug_h(cxt
, "syscall status set to: %d", status
));
2083 cxt
->syscall_status
= status
;
2088 * mnt_context_strerror
2091 * @bufsiz: size of the buffer
2093 * Not implemented yet.
2095 * Returns: 0 or negative number in case of error.
2097 int mnt_context_strerror(struct libmnt_context
*cxt
__attribute__((__unused__
)),
2098 char *buf
__attribute__((__unused__
)),
2099 size_t bufsiz
__attribute__((__unused__
)))
2101 /* TODO: based on cxt->syscall_errno or cxt->helper_status */
2106 * mnt_context_init_helper
2107 * @cxt: mount context
2108 * @action: MNT_ACT_{UMOUNT,MOUNT}
2109 * @flags: not used now
2111 * This function informs libmount that used from [u]mount.type helper.
2113 * The function also calls mnt_context_disable_helpers() to avoid recursive
2114 * mount.type helpers calling. It you really want to call another
2115 * mount.type helper from your helper, then you have to explicitly enable this
2118 * mnt_context_disable_helpers(cxt, FALSE);
2120 * Returns: 0 on success, negative number in case of error.
2122 int mnt_context_init_helper(struct libmnt_context
*cxt
, int action
,
2123 int flags
__attribute__((__unused__
)))
2129 rc
= mnt_context_disable_helpers(cxt
, TRUE
);
2131 rc
= set_flag(cxt
, MNT_FL_HELPER
, 1);
2133 cxt
->action
= action
;
2135 DBG(CXT
, mnt_debug_h(cxt
, "initialized for [u]mount.<type> helper [rc=%d]", rc
));
2140 * mnt_context_helper_setopt:
2142 * @c: getopt() result
2143 * @arg: getopt() optarg
2145 * This function applies the [u]mount.type command line option (for example parsed
2146 * by getopt or getopt_long) to @cxt. All unknown options are ignored and
2147 * then 1 is returned.
2149 * Returns: negative number on error, 1 if @c is unknown option, 0 on success.
2151 int mnt_context_helper_setopt(struct libmnt_context
*cxt
, int c
, char *arg
)
2154 switch(cxt
->action
) {
2156 return mnt_context_mount_setopt(cxt
, c
, arg
);
2157 case MNT_ACT_UMOUNT
:
2158 return mnt_context_umount_setopt(cxt
, c
, arg
);
2165 * mnt_context_is_fs_mounted:
2168 * @mounted: returns 1 for mounted and 0 for non-mounted filesystems
2170 * Please, read the mnt_table_is_fs_mounted() description!
2172 * Returns: 0 on success and negative number in case of error.
2174 int mnt_context_is_fs_mounted(struct libmnt_context
*cxt
,
2175 struct libmnt_fs
*fs
, int *mounted
)
2177 struct libmnt_table
*mtab
;
2181 if (!cxt
|| !fs
|| !mounted
)
2184 rc
= mnt_context_get_mtab(cxt
, &mtab
);
2188 *mounted
= mnt_table_is_fs_mounted(mtab
, fs
);
2192 static int mnt_context_add_child(struct libmnt_context
*cxt
, pid_t pid
)
2200 pids
= realloc(cxt
->children
, sizeof(pid_t
) * cxt
->nchildren
+ 1);
2204 DBG(CXT
, mnt_debug_h(cxt
, "add new child %d", pid
));
2205 cxt
->children
= pids
;
2206 cxt
->children
[cxt
->nchildren
++] = pid
;
2211 int mnt_fork_context(struct libmnt_context
*cxt
)
2217 if (!mnt_context_is_parent(cxt
))
2220 DBG(CXT
, mnt_debug_h(cxt
, "forking context"));
2227 case -1: /* error */
2228 DBG(CXT
, mnt_debug_h(cxt
, "fork failed %m"));
2232 cxt
->pid
= getpid();
2233 mnt_context_enable_fork(cxt
, FALSE
);
2234 DBG(CXT
, mnt_debug_h(cxt
, "child created"));
2238 rc
= mnt_context_add_child(cxt
, pid
);
2245 int mnt_context_wait_for_children(struct libmnt_context
*cxt
,
2246 int *nchildren
, int *nerrs
)
2254 assert(mnt_context_is_parent(cxt
));
2256 for (i
= 0; i
< cxt
->nchildren
; i
++) {
2257 pid_t pid
= cxt
->children
[i
];
2258 int rc
= 0, ret
= 0;
2263 DBG(CXT
, mnt_debug_h(cxt
,
2264 "waiting for child (%d/%d): %d",
2265 i
+ 1, cxt
->nchildren
, pid
));
2267 rc
= waitpid(pid
, &ret
, 0);
2269 } while (rc
== -1 && errno
== EINTR
);
2274 if (rc
!= -1 && nerrs
) {
2276 (*nerrs
) += WEXITSTATUS(ret
) == 0 ? 0 : 1;
2280 cxt
->children
[i
] = 0;
2284 free(cxt
->children
);
2285 cxt
->children
= NULL
;
2293 struct libmnt_lock
*lock
;
2295 static void lock_fallback(void)
2298 mnt_unlock_file(lock
);
2301 int test_mount(struct libmnt_test
*ts
, int argc
, char *argv
[])
2303 int idx
= 1, rc
= 0;
2304 struct libmnt_context
*cxt
;
2309 cxt
= mnt_new_context();
2313 if (!strcmp(argv
[idx
], "-o")) {
2314 mnt_context_set_options(cxt
, argv
[idx
+ 1]);
2317 if (!strcmp(argv
[idx
], "-t")) {
2318 /* TODO: use mnt_context_set_fstype_pattern() */
2319 mnt_context_set_fstype(cxt
, argv
[idx
+ 1]);
2323 if (argc
== idx
+ 1)
2324 /* mount <mountpont>|<device> */
2325 mnt_context_set_target(cxt
, argv
[idx
++]);
2327 else if (argc
== idx
+ 2) {
2328 /* mount <device> <mountpoint> */
2329 mnt_context_set_source(cxt
, argv
[idx
++]);
2330 mnt_context_set_target(cxt
, argv
[idx
++]);
2333 /* this is unnecessary! -- libmount is able to internally
2334 * create and manage the lock
2336 lock
= mnt_context_get_lock(cxt
);
2338 atexit(lock_fallback
);
2340 rc
= mnt_context_mount(cxt
);
2342 warn("failed to mount");
2344 printf("successfully mounted\n");
2346 lock
= NULL
; /* because we use atexit lock_fallback */
2347 mnt_free_context(cxt
);
2351 int test_umount(struct libmnt_test
*ts
, int argc
, char *argv
[])
2353 int idx
= 1, rc
= 0;
2354 struct libmnt_context
*cxt
;
2359 cxt
= mnt_new_context();
2363 if (!strcmp(argv
[idx
], "-t")) {
2364 mnt_context_set_fstype(cxt
, argv
[idx
+ 1]);
2368 if (!strcmp(argv
[idx
], "-f")) {
2369 mnt_context_enable_force(cxt
, TRUE
);
2373 if (!strcmp(argv
[idx
], "-l")) {
2374 mnt_context_enable_lazy(cxt
, TRUE
);
2378 if (!strcmp(argv
[idx
], "-r")) {
2379 mnt_context_enable_rdonly_umount(cxt
, TRUE
);
2383 if (argc
== idx
+ 1) {
2384 /* mount <mountpont>|<device> */
2385 mnt_context_set_target(cxt
, argv
[idx
++]);
2391 lock
= mnt_context_get_lock(cxt
);
2393 atexit(lock_fallback
);
2395 rc
= mnt_context_umount(cxt
);
2397 printf("failed to umount\n");
2399 printf("successfully umounted\n");
2401 lock
= NULL
; /* because we use atexit lock_fallback */
2402 mnt_free_context(cxt
);
2406 int test_flags(struct libmnt_test
*ts
, int argc
, char *argv
[])
2408 int idx
= 1, rc
= 0;
2409 struct libmnt_context
*cxt
;
2410 const char *opt
= NULL
;
2411 unsigned long flags
= 0;
2416 cxt
= mnt_new_context();
2420 if (!strcmp(argv
[idx
], "-o")) {
2421 mnt_context_set_options(cxt
, argv
[idx
+ 1]);
2425 if (argc
== idx
+ 1)
2426 /* mount <mountpont>|<device> */
2427 mnt_context_set_target(cxt
, argv
[idx
++]);
2429 rc
= mnt_context_prepare_mount(cxt
);
2431 printf("failed to prepare mount %s\n", strerror(-rc
));
2433 opt
= mnt_fs_get_options(cxt
->fs
);
2435 fprintf(stdout
, "options: %s\n", opt
);
2437 mnt_context_get_mflags(cxt
, &flags
);
2438 fprintf(stdout
, "flags: %08lx\n", flags
);
2440 mnt_free_context(cxt
);
2444 int test_mountall(struct libmnt_test
*ts
, int argc
, char *argv
[])
2446 struct libmnt_context
*cxt
;
2447 struct libmnt_iter
*itr
;
2448 struct libmnt_fs
*fs
;
2449 int mntrc
, ignored
, idx
= 1;
2451 cxt
= mnt_new_context();
2452 itr
= mnt_new_iter(MNT_ITER_FORWARD
);
2458 if (argv
[idx
] && !strcmp(argv
[idx
], "-O")) {
2459 mnt_context_set_options_pattern(cxt
, argv
[idx
+ 1]);
2462 if (argv
[idx
] && !strcmp(argv
[idx
], "-t")) {
2463 mnt_context_set_fstype_pattern(cxt
, argv
[idx
+ 1]);
2468 while (mnt_context_next_mount(cxt
, itr
, &fs
, &mntrc
, &ignored
) == 0) {
2470 const char *tgt
= mnt_fs_get_target(fs
);
2473 printf("%s: ignored: not match\n", tgt
);
2474 else if (ignored
== 2)
2475 printf("%s: ignored: already mounted\n", tgt
);
2477 else if (!mnt_context_get_status(cxt
)) {
2480 warn("%s: mount failed", tgt
);
2482 warnx("%s: mount failed", tgt
);
2484 printf("%s: successfully mounted\n", tgt
);
2487 mnt_free_context(cxt
);
2491 int main(int argc
, char *argv
[])
2493 struct libmnt_test tss
[] = {
2494 { "--mount", test_mount
, "[-o <opts>] [-t <type>] <spec>|<src> <target>" },
2495 { "--umount", test_umount
, "[-t <type>] [-f][-l][-r] <src>|<target>" },
2496 { "--mount-all", test_mountall
, "[-O <pattern>] [-t <pattern] mount all filesystems from fstab" },
2497 { "--flags", test_flags
, "[-o <opts>] <spec>" },
2500 umask(S_IWGRP
|S_IWOTH
); /* to be compatible with mount(8) */
2502 return mnt_run_test(tss
, argc
, argv
);
2505 #endif /* TEST_PROGRAM */