1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 * This file is part of libmount from util-linux project.
5 * Copyright (C) 2010-2018 Karel Zak <kzak@redhat.com>
7 * libmount is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
14 * SECTION: context-mount
15 * @title: Mount context
16 * @short_description: high-level API to mount operation.
19 #ifdef HAVE_LIBSELINUX
20 #include <selinux/selinux.h>
21 #include <selinux/context.h>
25 #include <sys/mount.h>
27 #include "linux_version.h"
32 * Kernel supports only one MS_PROPAGATION flag change by one mount(2) syscall,
33 * to bypass this restriction we call mount(2) per flag. It's really not a perfect
34 * solution, but it's the same like to execute multiple mount(8) commands.
36 * We use cxt->addmounts (additional mounts) list to keep order of the requested
39 struct libmnt_addmount
*mnt_new_addmount(void)
41 struct libmnt_addmount
*ad
= calloc(1, sizeof(*ad
));
45 INIT_LIST_HEAD(&ad
->mounts
);
49 void mnt_free_addmount(struct libmnt_addmount
*ad
)
53 list_del(&ad
->mounts
);
57 static int mnt_context_append_additional_mount(struct libmnt_context
*cxt
,
58 struct libmnt_addmount
*ad
)
63 if (!list_empty(&ad
->mounts
))
66 DBG(CXT
, ul_debugobj(cxt
,
67 "mount: add additional flag: 0x%08lx",
70 list_add_tail(&ad
->mounts
, &cxt
->addmounts
);
75 * add additional mount(2) syscall requests when necessary to set propagation flags
76 * after regular mount(2).
78 static int init_propagation(struct libmnt_context
*cxt
)
81 char *opts
= (char *) mnt_fs_get_vfs_options(cxt
->fs
);
83 struct libmnt_optmap
const *maps
[1];
89 DBG(CXT
, ul_debugobj(cxt
, "mount: initialize additional propagation mounts"));
91 maps
[0] = mnt_get_builtin_optmap(MNT_LINUX_MAP
);
93 while (!mnt_optstr_next_option(&opts
, &name
, &namesz
, NULL
, NULL
)) {
94 const struct libmnt_optmap
*ent
;
95 struct libmnt_addmount
*ad
;
98 if (!mnt_optmap_get_entry(maps
, 1, name
, namesz
, &ent
) || !ent
)
101 DBG(CXT
, ul_debugobj(cxt
, " checking %s", ent
->name
));
103 /* Note that MS_REC may be used for more flags, so we have to keep
104 * track about number of recursive options to keep the MS_REC in the
105 * mountflags if necessary.
107 if (ent
->id
& MS_REC
)
110 if (!(ent
->id
& MS_PROPAGATION
))
113 ad
= mnt_new_addmount();
117 ad
->mountflags
= ent
->id
;
118 DBG(CXT
, ul_debugobj(cxt
, " adding extra mount(2) call for %s", ent
->name
));
119 rc
= mnt_context_append_additional_mount(cxt
, ad
);
123 DBG(CXT
, ul_debugobj(cxt
, " removing %s from primary mount(2) call", ent
->name
));
124 cxt
->mountflags
&= ~ent
->id
;
126 if (ent
->id
& MS_REC
)
131 cxt
->mountflags
|= MS_REC
;
137 * add additional mount(2) syscall request to implement "bind,<flags>", the first regular
138 * mount(2) is the "bind" operation, the second is "remount,bind,<flags>" call.
140 static int init_bind_remount(struct libmnt_context
*cxt
)
142 struct libmnt_addmount
*ad
;
146 assert(cxt
->mountflags
& MS_BIND
);
147 assert(!(cxt
->mountflags
& MS_REMOUNT
));
149 DBG(CXT
, ul_debugobj(cxt
, "mount: initialize additional ro,bind mount"));
151 ad
= mnt_new_addmount();
155 ad
->mountflags
= cxt
->mountflags
;
156 ad
->mountflags
|= (MS_REMOUNT
| MS_BIND
);
158 rc
= mnt_context_append_additional_mount(cxt
, ad
);
165 #if defined(HAVE_LIBSELINUX) || defined(HAVE_SMACK)
166 struct libmnt_optname
{
171 #define DEF_OPTNAME(n) { .name = n, .namesz = sizeof(n) - 1 }
172 #define DEF_OPTNAME_LAST { .name = NULL }
174 static int is_option(const char *name
, size_t namesz
,
175 const struct libmnt_optname
*names
)
177 const struct libmnt_optname
*p
;
179 for (p
= names
; p
&& p
->name
; p
++) {
180 if (p
->namesz
== namesz
181 && strncmp(name
, p
->name
, namesz
) == 0)
187 #endif /* HAVE_LIBSELINUX || HAVE_SMACK */
190 * this has to be called after mnt_context_evaluate_permissions()
192 static int fix_optstr(struct libmnt_context
*cxt
)
195 struct libmnt_ns
*ns_old
;
198 size_t namesz
, valsz
;
199 struct libmnt_fs
*fs
;
200 #ifdef HAVE_LIBSELINUX
201 int se_fix
= 0, se_rem
= 0;
202 static const struct libmnt_optname selinux_options
[] = {
203 DEF_OPTNAME("context"),
204 DEF_OPTNAME("fscontext"),
205 DEF_OPTNAME("defcontext"),
206 DEF_OPTNAME("rootcontext"),
207 DEF_OPTNAME("seclabel"),
213 static const struct libmnt_optname smack_options
[] = {
214 DEF_OPTNAME("smackfsdef"),
215 DEF_OPTNAME("smackfsfloor"),
216 DEF_OPTNAME("smackfshat"),
217 DEF_OPTNAME("smackfsroot"),
218 DEF_OPTNAME("smackfstransmute"),
223 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
225 if (!cxt
->fs
|| (cxt
->flags
& MNT_FL_MOUNTOPTS_FIXED
))
228 DBG(CXT
, ul_debugobj(cxt
, "mount: fixing optstr"));
233 * The "user" options is our business (so we can modify the option),
234 * the exception is command line for /sbin/mount.<type> helpers. Let's
235 * save the original user=<name> to call the helpers with an unchanged
238 if (cxt
->user_mountflags
& MNT_MS_USER
) {
239 if (!mnt_optstr_get_option(fs
->user_optstr
,
240 "user", &val
, &valsz
) && val
) {
241 cxt
->orig_user
= strndup(val
, valsz
);
242 if (!cxt
->orig_user
) {
247 cxt
->flags
|= MNT_FL_SAVED_USER
;
251 * Sync mount options with mount flags
253 DBG(CXT
, ul_debugobj(cxt
, "mount: fixing vfs optstr"));
254 rc
= mnt_optstr_apply_flags(&fs
->vfs_optstr
, cxt
->mountflags
,
255 mnt_get_builtin_optmap(MNT_LINUX_MAP
));
259 DBG(CXT
, ul_debugobj(cxt
, "mount: fixing user optstr"));
260 rc
= mnt_optstr_apply_flags(&fs
->user_optstr
, cxt
->user_mountflags
,
261 mnt_get_builtin_optmap(MNT_USERSPACE_MAP
));
265 if (fs
->vfs_optstr
&& *fs
->vfs_optstr
== '\0') {
266 free(fs
->vfs_optstr
);
267 fs
->vfs_optstr
= NULL
;
269 if (fs
->user_optstr
&& *fs
->user_optstr
== '\0') {
270 free(fs
->user_optstr
);
271 fs
->user_optstr
= NULL
;
273 if (cxt
->mountflags
& MS_PROPAGATION
) {
274 rc
= init_propagation(cxt
);
278 if ((cxt
->mountflags
& MS_BIND
)
279 && (cxt
->mountflags
& MNT_BIND_SETTABLE
)
280 && !(cxt
->mountflags
& MS_REMOUNT
)) {
281 rc
= init_bind_remount(cxt
);
286 next
= fs
->fs_optstr
;
288 #ifdef HAVE_LIBSELINUX
289 if (!is_selinux_enabled())
290 /* Always remove SELinux garbage if SELinux disabled */
292 else if (cxt
->mountflags
& MS_REMOUNT
)
294 * Linux kernel < 2.6.39 does not allow to remount with any
295 * selinux specific mount options.
297 * Kernel 2.6.39 commits: ff36fe2c845cab2102e4826c1ffa0a6ebf487c65
298 * 026eb167ae77244458fa4b4b9fc171209c079ba7
299 * fix this odd behavior, so we don't have to care about it in
302 se_rem
= get_linux_version() < KERNEL_VERSION(2, 6, 39);
304 /* For normal mount, contexts are translated */
308 /* de-duplicate SELinux options */
309 const struct libmnt_optname
*p
;
310 for (p
= selinux_options
; p
&& p
->name
; p
++)
311 mnt_optstr_deduplicate_option(&fs
->fs_optstr
, p
->name
);
315 if (access("/sys/fs/smackfs", F_OK
) != 0)
318 while (!mnt_optstr_next_option(&next
, &name
, &namesz
, &val
, &valsz
)) {
320 if (namesz
== 3 && !strncmp(name
, "uid", 3))
321 rc
= mnt_optstr_fix_uid(&fs
->fs_optstr
, val
, valsz
, &next
);
322 else if (namesz
== 3 && !strncmp(name
, "gid", 3))
323 rc
= mnt_optstr_fix_gid(&fs
->fs_optstr
, val
, valsz
, &next
);
324 #ifdef HAVE_LIBSELINUX
325 else if ((se_rem
|| se_fix
)
326 && is_option(name
, namesz
, selinux_options
)) {
329 /* remove context= option */
331 rc
= mnt_optstr_remove_option_at(&fs
->fs_optstr
,
335 } else if (se_fix
&& val
&& valsz
)
336 /* translate selinux contexts */
337 rc
= mnt_optstr_fix_secontext(&fs
->fs_optstr
,
342 else if (sm_rem
&& is_option(name
, namesz
, smack_options
)) {
345 rc
= mnt_optstr_remove_option_at(&fs
->fs_optstr
,
347 val
? val
+ valsz
: name
+ namesz
);
355 if (!rc
&& cxt
->restricted
&& (cxt
->user_mountflags
& MNT_MS_USER
)) {
356 ns_old
= mnt_context_switch_origin_ns(cxt
);
358 return -MNT_ERR_NAMESPACE
;
360 rc
= mnt_optstr_fix_user(&fs
->user_optstr
);
362 if (!mnt_context_switch_ns(cxt
, ns_old
))
363 return -MNT_ERR_NAMESPACE
;
366 /* refresh merged optstr */
369 fs
->optstr
= mnt_fs_strdup_options(fs
);
371 cxt
->flags
|= MNT_FL_MOUNTOPTS_FIXED
;
373 DBG(CXT
, ul_debugobj(cxt
, "fixed options [rc=%d]: "
374 "vfs: '%s' fs: '%s' user: '%s', optstr: '%s'", rc
,
375 fs
->vfs_optstr
, fs
->fs_optstr
, fs
->user_optstr
, fs
->optstr
));
378 rc
= -MNT_ERR_MOUNTOPT
;
383 * Converts the already evaluated and fixed options to the form that is compatible
384 * with /sbin/mount.type helpers.
386 static int generate_helper_optstr(struct libmnt_context
*cxt
, char **optstr
)
388 struct libmnt_optmap
const *maps
[2];
389 char *next
, *name
, *val
;
390 size_t namesz
, valsz
;
397 DBG(CXT
, ul_debugobj(cxt
, "mount: generate helper mount options"));
399 *optstr
= mnt_fs_strdup_options(cxt
->fs
);
403 if ((cxt
->user_mountflags
& MNT_MS_USER
) ||
404 (cxt
->user_mountflags
& MNT_MS_USERS
)) {
406 * This is unnecessary for real user-mounts as mount.<type>
407 * helpers always have to follow fstab rather than mount
408 * options on the command line.
410 * However, if you call mount.<type> as root, then the helper follows
411 * the command line. If there is (for example) "user,exec" in fstab,
412 * then we have to manually append the "exec" back to the options
413 * string, because there is nothing like MS_EXEC (we only have
414 * MS_NOEXEC in mount flags and we don't care about the original
415 * mount string in libmount for VFS options).
417 if (!(cxt
->mountflags
& MS_NOEXEC
))
418 mnt_optstr_append_option(optstr
, "exec", NULL
);
419 if (!(cxt
->mountflags
& MS_NOSUID
))
420 mnt_optstr_append_option(optstr
, "suid", NULL
);
421 if (!(cxt
->mountflags
& MS_NODEV
))
422 mnt_optstr_append_option(optstr
, "dev", NULL
);
426 if (cxt
->flags
& MNT_FL_SAVED_USER
)
427 rc
= mnt_optstr_set_option(optstr
, "user", cxt
->orig_user
);
431 /* remove userspace options with MNT_NOHLPS flag */
432 maps
[0] = mnt_get_builtin_optmap(MNT_USERSPACE_MAP
);
433 maps
[1] = mnt_get_builtin_optmap(MNT_LINUX_MAP
);
436 while (!mnt_optstr_next_option(&next
, &name
, &namesz
, &val
, &valsz
)) {
437 const struct libmnt_optmap
*ent
;
439 mnt_optmap_get_entry(maps
, 2, name
, namesz
, &ent
);
440 if (ent
&& ent
->id
&& (ent
->mask
& MNT_NOHLPS
)) {
442 rc
= mnt_optstr_remove_option_at(optstr
, name
,
443 val
? val
+ valsz
: name
+ namesz
);
457 * this has to be called before fix_optstr()
459 * Note that user=<name> may be used by some filesystems as a filesystem
460 * specific option (e.g. cifs). Yes, developers of such filesystems have
461 * allocated pretty hot place in hell...
463 static int evaluate_permissions(struct libmnt_context
*cxt
)
465 unsigned long u_flags
= 0;
468 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
473 DBG(CXT
, ul_debugobj(cxt
, "mount: evaluating permissions"));
475 mnt_context_get_user_mflags(cxt
, &u_flags
);
477 if (!mnt_context_is_restricted(cxt
)) {
481 cxt
->user_mountflags
&= ~MNT_MS_OWNER
;
482 cxt
->user_mountflags
&= ~MNT_MS_GROUP
;
487 if (!mnt_context_tab_applied(cxt
))
489 DBG(CXT
, ul_debugobj(cxt
, "perms: fstab not applied, ignore user mount"));
494 * MS_OWNERSECURE and MS_SECURE mount options are already
495 * applied by mnt_optstr_get_flags() in mnt_context_merge_mflags()
496 * if "user" (but no user=<name> !) options is set.
498 * Let's ignore all user=<name> (if <name> is set) requests.
500 if (cxt
->user_mountflags
& MNT_MS_USER
) {
503 if (!mnt_optstr_get_option(cxt
->fs
->user_optstr
,
504 "user", NULL
, &valsz
) && valsz
) {
506 DBG(CXT
, ul_debugobj(cxt
, "perms: user=<name> detected, ignore"));
507 cxt
->user_mountflags
&= ~MNT_MS_USER
;
512 * MS_OWNER: Allow owners to mount when fstab contains the
513 * owner option. Note that this should never be used in a high
514 * security environment, but may be useful to give people at
515 * the console the possibility of mounting a floppy. MS_GROUP:
516 * Allow members of device group to mount. (Martin Dickopp)
518 if (u_flags
& (MNT_MS_OWNER
| MNT_MS_GROUP
)) {
520 struct libmnt_cache
*cache
= NULL
;
522 const char *srcpath
= mnt_fs_get_srcpath(cxt
->fs
);
524 if (!srcpath
) { /* Ah... source is TAG */
525 cache
= mnt_context_get_cache(cxt
);
526 xsrc
= mnt_resolve_spec(
527 mnt_context_get_source(cxt
),
532 DBG(CXT
, ul_debugobj(cxt
, "perms: src undefined"));
536 if (strncmp(srcpath
, "/dev/", 5) == 0 &&
537 stat(srcpath
, &sb
) == 0 &&
538 (((u_flags
& MNT_MS_OWNER
) && getuid() == sb
.st_uid
) ||
539 ((u_flags
& MNT_MS_GROUP
) && mnt_in_group(sb
.st_gid
))))
541 cxt
->user_mountflags
|= MNT_MS_USER
;
547 if (!(cxt
->user_mountflags
& (MNT_MS_USER
| MNT_MS_USERS
))) {
548 DBG(CXT
, ul_debugobj(cxt
, "permissions evaluation ends with -EPERMS"));
557 * mnt_context_helper_setopt() backend
559 * This function applies the mount.type command line option (for example parsed
560 * by getopt() or getopt_long()) to @cxt. All unknown options are ignored and
561 * then 1 is returned.
563 * Returns: negative number on error, 1 if @c is unknown option, 0 on success.
565 int mnt_context_mount_setopt(struct libmnt_context
*cxt
, int c
, char *arg
)
570 assert(cxt
->action
== MNT_ACT_MOUNT
);
574 rc
= mnt_context_enable_fake(cxt
, TRUE
);
577 rc
= mnt_context_disable_mtab(cxt
, TRUE
);
580 rc
= mnt_context_append_options(cxt
, "ro");
583 rc
= mnt_context_enable_verbose(cxt
, TRUE
);
586 rc
= mnt_context_append_options(cxt
, "rw");
590 rc
= mnt_context_append_options(cxt
, arg
);
593 rc
= mnt_context_enable_sloppy(cxt
, TRUE
);
597 rc
= mnt_context_set_fstype(cxt
, arg
);
601 rc
= mnt_context_set_target_ns(cxt
, arg
);
610 static int exec_helper(struct libmnt_context
*cxt
)
612 char *o
= NULL
, *namespace = NULL
;
613 struct libmnt_ns
*ns_tgt
= mnt_context_get_target_ns(cxt
);
620 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
622 DBG(CXT
, ul_debugobj(cxt
, "mount: executing helper %s", cxt
->helper
));
624 rc
= generate_helper_optstr(cxt
, &o
);
629 && asprintf(&namespace, "/proc/%i/fd/%i",
630 getpid(), ns_tgt
->fd
) == -1) {
641 const char *args
[14], *type
;
644 if (setgid(getgid()) < 0)
647 if (setuid(getuid()) < 0)
650 if (!mnt_context_switch_origin_ns(cxt
))
653 type
= mnt_fs_get_fstype(cxt
->fs
);
655 args
[i
++] = cxt
->helper
; /* 1 */
656 args
[i
++] = mnt_fs_get_srcpath(cxt
->fs
);/* 2 */
657 args
[i
++] = mnt_fs_get_target(cxt
->fs
); /* 3 */
659 if (mnt_context_is_sloppy(cxt
))
660 args
[i
++] = "-s"; /* 4 */
661 if (mnt_context_is_fake(cxt
))
662 args
[i
++] = "-f"; /* 5 */
663 if (mnt_context_is_nomtab(cxt
))
664 args
[i
++] = "-n"; /* 6 */
665 if (mnt_context_is_verbose(cxt
))
666 args
[i
++] = "-v"; /* 7 */
668 args
[i
++] = "-o"; /* 8 */
669 args
[i
++] = o
; /* 9 */
673 && !endswith(cxt
->helper
, type
)) {
674 args
[i
++] = "-t"; /* 10 */
675 args
[i
++] = type
; /* 11 */
678 args
[i
++] = "-N"; /* 11 */
679 args
[i
++] = namespace; /* 12 */
681 args
[i
] = NULL
; /* 13 */
682 for (i
= 0; args
[i
]; i
++)
683 DBG(CXT
, ul_debugobj(cxt
, "argv[%d] = \"%s\"",
686 execv(cxt
->helper
, (char * const *) args
);
693 if (waitpid(pid
, &st
, 0) == (pid_t
) -1) {
694 cxt
->helper_status
= -1;
697 cxt
->helper_status
= WIFEXITED(st
) ? WEXITSTATUS(st
) : -1;
698 cxt
->helper_exec_status
= rc
= 0;
700 DBG(CXT
, ul_debugobj(cxt
, "%s executed [status=%d, rc=%d%s]",
702 cxt
->helper_status
, rc
,
703 rc
? " waitpid failed" : ""));
708 cxt
->helper_exec_status
= rc
= -errno
;
709 DBG(CXT
, ul_debugobj(cxt
, "fork() failed"));
717 static int do_mount_additional(struct libmnt_context
*cxt
,
730 list_for_each(p
, &cxt
->addmounts
) {
732 struct libmnt_addmount
*ad
=
733 list_entry(p
, struct libmnt_addmount
, mounts
);
735 DBG(CXT
, ul_debugobj(cxt
, "mount(2) changing flag: 0x%08lx %s",
737 ad
->mountflags
& MS_REC
? " (recursive)" : ""));
739 rc
= mount("none", target
, NULL
,
740 ad
->mountflags
| (flags
& MS_SILENT
), NULL
);
744 DBG(CXT
, ul_debugobj(cxt
,
745 "mount(2) failed [errno=%d %m]",
755 * The default is to use fstype from cxt->fs, this could be overwritten by
756 * @try_type argument. If @try_type is specified then mount with MS_SILENT.
758 * Returns: 0 on success,
759 * >0 in case of mount(2) error (returns syscall errno),
760 * <0 in case of other errors.
762 static int do_mount(struct libmnt_context
*cxt
, const char *try_type
)
765 const char *src
, *target
, *type
;
770 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
772 if (try_type
&& !cxt
->helper
) {
773 rc
= mnt_context_prepare_helper(cxt
, "mount", try_type
);
778 flags
= cxt
->mountflags
;
779 src
= mnt_fs_get_srcpath(cxt
->fs
);
780 target
= mnt_fs_get_target(cxt
->fs
);
783 rc
= exec_helper(cxt
);
785 if (mnt_context_helper_executed(cxt
)
786 && mnt_context_get_helper_status(cxt
) == 0
787 && !list_empty(&cxt
->addmounts
)
788 && do_mount_additional(cxt
, target
, flags
, NULL
))
790 return -MNT_ERR_APPLYFLAGS
;
797 /* unnecessary, should be already resolved in
798 * mnt_context_prepare_srcpath(), but to be sure... */
799 DBG(CXT
, ul_debugobj(cxt
, "WARNING: source is NULL -- using \"none\"!"));
802 type
= try_type
? : mnt_fs_get_fstype(cxt
->fs
);
807 DBG(CXT
, ul_debugobj(cxt
, "%smount(2) "
808 "[source=%s, target=%s, type=%s, "
809 " mountflags=0x%08lx, mountdata=%s]",
810 mnt_context_is_fake(cxt
) ? "(FAKE) " : "",
812 flags
, cxt
->mountdata
? "yes" : "<none>"));
814 if (mnt_context_is_fake(cxt
)) {
818 cxt
->syscall_status
= 0;
820 } else if (mnt_context_propagation_only(cxt
)) {
822 * propagation flags *only*
824 if (do_mount_additional(cxt
, target
, flags
, &cxt
->syscall_status
))
825 return -MNT_ERR_APPLYFLAGS
;
830 if (mount(src
, target
, type
, flags
, cxt
->mountdata
)) {
831 cxt
->syscall_status
= -errno
;
832 DBG(CXT
, ul_debugobj(cxt
, "mount(2) failed [errno=%d %m]",
833 -cxt
->syscall_status
));
834 return -cxt
->syscall_status
;
836 DBG(CXT
, ul_debugobj(cxt
, " success"));
837 cxt
->syscall_status
= 0;
840 * additional mounts for extra propagation flags
842 if (!list_empty(&cxt
->addmounts
)
843 && do_mount_additional(cxt
, target
, flags
, NULL
)) {
845 /* TODO: call umount? */
846 return -MNT_ERR_APPLYFLAGS
;
850 if (try_type
&& cxt
->update
) {
851 struct libmnt_fs
*fs
= mnt_update_get_fs(cxt
->update
);
853 rc
= mnt_fs_set_fstype(fs
, try_type
);
859 /* try mount(2) for all items in comma separated list of the filesystem @types */
860 static int do_mount_by_types(struct libmnt_context
*cxt
, const char *types
)
866 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
868 DBG(CXT
, ul_debugobj(cxt
, "trying to mount by FS list '%s'", types
));
870 p0
= p
= strdup(types
);
874 char *autotype
= NULL
;
875 char *end
= strchr(p
, ',');
880 DBG(CXT
, ul_debugobj(cxt
, "-->trying '%s'", p
));
882 /* Let's support things like "udf,iso9660,auto" */
883 if (strcmp(p
, "auto") == 0) {
884 rc
= mnt_context_guess_srcpath_fstype(cxt
, &autotype
);
886 DBG(CXT
, ul_debugobj(cxt
, "failed to guess FS type [rc=%d]", rc
));
892 DBG(CXT
, ul_debugobj(cxt
, " --> '%s'", p
));
896 rc
= do_mount(cxt
, p
);
897 p
= end
? end
+ 1 : NULL
;
899 } while (!mnt_context_get_status(cxt
) && p
);
906 static int do_mount_by_pattern(struct libmnt_context
*cxt
, const char *pattern
)
908 int neg
= pattern
&& strncmp(pattern
, "no", 2) == 0;
910 char **filesystems
, **fp
;
911 struct libmnt_ns
*ns_old
;
914 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
917 * Use the pattern as list of the filesystems
919 if (!neg
&& pattern
) {
920 DBG(CXT
, ul_debugobj(cxt
, "use FS pattern as FS list"));
921 return do_mount_by_types(cxt
, pattern
);
924 DBG(CXT
, ul_debugobj(cxt
, "trying to mount by FS pattern '%s'", pattern
));
927 * Apply pattern to /etc/filesystems and /proc/filesystems
929 ns_old
= mnt_context_switch_origin_ns(cxt
);
931 return -MNT_ERR_NAMESPACE
;
932 rc
= mnt_get_filesystems(&filesystems
, neg
? pattern
: NULL
);
933 if (!mnt_context_switch_ns(cxt
, ns_old
))
934 return -MNT_ERR_NAMESPACE
;
938 if (filesystems
== NULL
)
939 return -MNT_ERR_NOFSTYPE
;
941 for (fp
= filesystems
; *fp
; fp
++) {
942 rc
= do_mount(cxt
, *fp
);
943 if (mnt_context_get_status(cxt
))
945 if (mnt_context_get_syscall_errno(cxt
) != EINVAL
&&
946 mnt_context_get_syscall_errno(cxt
) != ENODEV
)
949 mnt_free_filesystems(filesystems
);
954 * mnt_context_prepare_mount:
957 * Prepare context for mounting, unnecessary for mnt_context_mount().
959 * Returns: negative number on error, zero on success
961 int mnt_context_prepare_mount(struct libmnt_context
*cxt
)
964 struct libmnt_ns
*ns_old
;
966 if (!cxt
|| !cxt
->fs
|| mnt_fs_is_swaparea(cxt
->fs
))
968 if (!mnt_fs_get_source(cxt
->fs
) && !mnt_fs_get_target(cxt
->fs
))
970 if (cxt
->flags
& MNT_FL_PREPARED
)
973 assert(cxt
->helper_exec_status
== 1);
974 assert(cxt
->syscall_status
== 1);
976 cxt
->action
= MNT_ACT_MOUNT
;
978 ns_old
= mnt_context_switch_target_ns(cxt
);
980 return -MNT_ERR_NAMESPACE
;
982 DBG(CXT
, ul_debugobj(cxt
, "mount: preparing"));
984 rc
= mnt_context_apply_fstab(cxt
);
986 rc
= mnt_context_merge_mflags(cxt
);
988 rc
= evaluate_permissions(cxt
);
990 rc
= fix_optstr(cxt
);
992 rc
= mnt_context_prepare_srcpath(cxt
);
994 rc
= mnt_context_prepare_target(cxt
);
996 rc
= mnt_context_guess_fstype(cxt
);
998 rc
= mnt_context_prepare_helper(cxt
, "mount", NULL
);
1000 DBG(CXT
, ul_debugobj(cxt
, "mount: preparing failed"));
1003 cxt
->flags
|= MNT_FL_PREPARED
;
1006 if (!mnt_context_switch_ns(cxt
, ns_old
))
1007 return -MNT_ERR_NAMESPACE
;
1013 * mnt_context_do_mount
1016 * Call mount(2) or mount.type helper. Unnecessary for mnt_context_mount().
1018 * Note that this function could be called only once. If you want to mount
1019 * another source or target, then you have to call mnt_reset_context().
1021 * If you want to call mount(2) for the same source and target with different
1022 * mount flags or fstype, then call mnt_context_reset_status() and then try
1023 * again mnt_context_do_mount().
1025 * WARNING: non-zero return code does not mean that mount(2) syscall or
1026 * mount.type helper wasn't successfully called.
1028 * Check mnt_context_get_status() after error! See mnt_context_mount() for more
1029 * details about errors and warnings.
1031 * Returns: 0 on success;
1032 * >0 in case of mount(2) error (returns syscall errno),
1033 * <0 in case of other errors.
1035 int mnt_context_do_mount(struct libmnt_context
*cxt
)
1039 struct libmnt_ns
*ns_old
;
1043 assert(cxt
->helper_exec_status
== 1);
1044 assert(cxt
->syscall_status
== 1);
1045 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
1046 assert((cxt
->flags
& MNT_FL_PREPARED
));
1047 assert((cxt
->action
== MNT_ACT_MOUNT
));
1049 DBG(CXT
, ul_debugobj(cxt
, "mount: do mount"));
1051 if (!(cxt
->flags
& MNT_FL_MOUNTDATA
))
1052 cxt
->mountdata
= (char *) mnt_fs_get_fs_options(cxt
->fs
);
1054 ns_old
= mnt_context_switch_target_ns(cxt
);
1056 return -MNT_ERR_NAMESPACE
;
1058 type
= mnt_fs_get_fstype(cxt
->fs
);
1060 if (strchr(type
, ','))
1061 /* this only happens if fstab contains a list of filesystems */
1062 res
= do_mount_by_types(cxt
, type
);
1064 res
= do_mount(cxt
, NULL
);
1066 res
= do_mount_by_pattern(cxt
, cxt
->fstype_pattern
);
1068 #ifdef USE_LIBMOUNT_SUPPORT_MTAB
1069 if (mnt_context_get_status(cxt
)
1070 && !mnt_context_is_fake(cxt
)
1072 && mnt_context_mtab_writable(cxt
)) {
1076 DBG(CXT
, ul_debugobj(cxt
, "checking for RDONLY mismatch"));
1079 * Mounted by mount(2), do some post-mount checks
1081 * Kernel allows to use MS_RDONLY for bind mounts, but the
1082 * read-only request could be silently ignored. Check it to
1083 * avoid 'ro' in mtab and 'rw' in /proc/mounts.
1085 if ((cxt
->mountflags
& MS_BIND
)
1086 && (cxt
->mountflags
& MS_RDONLY
)) {
1089 is_rdonly
= mnt_is_readonly(mnt_context_get_target(cxt
));
1091 mnt_context_set_mflags(cxt
, cxt
->mountflags
& ~MS_RDONLY
);
1095 /* Kernel can silently add MS_RDONLY flag when mounting file
1096 * system that does not have write support. Check this to avoid
1097 * 'ro' in /proc/mounts and 'rw' in mtab.
1099 if (!(cxt
->mountflags
& (MS_RDONLY
| MS_MOVE
))
1100 && !mnt_context_propagation_only(cxt
)) {
1103 is_rdonly
= mnt_is_readonly(mnt_context_get_target(cxt
));
1105 mnt_context_set_mflags(cxt
, cxt
->mountflags
| MS_RDONLY
);
1109 if (!mnt_context_switch_ns(cxt
, ns_old
))
1110 return -MNT_ERR_NAMESPACE
;
1116 * mnt_context_finalize_mount:
1119 * Mtab update, etc. Unnecessary for mnt_context_mount(), but should be called
1120 * after mnt_context_do_mount(). See also mnt_context_set_syscall_status().
1122 * Returns: negative number on error, 0 on success.
1124 int mnt_context_finalize_mount(struct libmnt_context
*cxt
)
1130 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
1131 assert((cxt
->flags
& MNT_FL_PREPARED
));
1133 rc
= mnt_context_prepare_update(cxt
);
1135 rc
= mnt_context_update_tabs(cxt
);
1140 * mnt_context_mount:
1141 * @cxt: mount context
1143 * High-level, mounts the filesystem by mount(2) or fork()+exec(/sbin/mount.type).
1145 * This is similar to:
1147 * mnt_context_prepare_mount(cxt);
1148 * mnt_context_do_mount(cxt);
1149 * mnt_context_finalize_mount(cxt);
1151 * See also mnt_context_disable_helpers().
1153 * Note that this function should be called only once. If you want to mount with
1154 * different settings, then you have to call mnt_reset_context(). It's NOT enough
1155 * to call mnt_context_reset_status(). If you want to call this function more than
1156 * once, the whole context has to be reset.
1158 * WARNING: non-zero return code does not mean that mount(2) syscall or
1159 * mount.type helper wasn't successfully called.
1161 * Always use mnt_context_get_status():
1165 * rc = mnt_context_mount(cxt);
1167 * if (mnt_context_helper_executed(cxt))
1168 * return mnt_context_get_helper_status(cxt);
1169 * if (rc == 0 && mnt_context_get_status(cxt) == 1)
1170 * return MNT_EX_SUCCESS;
1171 * return MNT_EX_FAIL;
1173 * </informalexample>
1175 * or mnt_context_get_excode() to generate mount(8) compatible error
1176 * or warning message:
1180 * rc = mnt_context_mount(cxt);
1181 * rc = mnt_context_get_excode(cxt, rc, buf, sizeof(buf));
1183 * warnx(_("%s: %s"), mnt_context_get_target(cxt), buf);
1184 * return rc; // MNT_EX_*
1186 * </informalexample>
1188 * Returns: 0 on success;
1189 * >0 in case of mount(2) error (returns syscall errno),
1190 * <0 in case of other errors.
1192 int mnt_context_mount(struct libmnt_context
*cxt
)
1195 struct libmnt_ns
*ns_old
;
1199 assert(cxt
->helper_exec_status
== 1);
1200 assert(cxt
->syscall_status
== 1);
1202 ns_old
= mnt_context_switch_target_ns(cxt
);
1204 return -MNT_ERR_NAMESPACE
;
1207 rc
= mnt_context_prepare_mount(cxt
);
1209 rc
= mnt_context_prepare_update(cxt
);
1211 rc
= mnt_context_do_mount(cxt
);
1213 rc
= mnt_context_update_tabs(cxt
);
1216 * Read-only device; try mount filesystem read-only
1218 if ((rc
== -EROFS
&& !mnt_context_syscall_called(cxt
)) /* before syscall; rdonly loopdev */
1219 || mnt_context_get_syscall_errno(cxt
) == EROFS
/* syscall failed with EROFS */
1220 || mnt_context_get_syscall_errno(cxt
) == EACCES
) /* syscall failed with EACCES */
1222 unsigned long mflags
= 0;
1224 mnt_context_get_mflags(cxt
, &mflags
);
1226 if (!(mflags
& MS_RDONLY
) /* not yet RDONLY */
1227 && !(mflags
& MS_REMOUNT
) /* not remount */
1228 && !(mflags
& MS_BIND
) /* not bin mount */
1229 && !mnt_context_is_rwonly_mount(cxt
)) { /* no explicit read-write */
1231 assert(!(cxt
->flags
& MNT_FL_FORCED_RDONLY
));
1232 DBG(CXT
, ul_debugobj(cxt
, "write-protected source, trying RDONLY."));
1234 mnt_context_reset_status(cxt
);
1235 mnt_context_set_mflags(cxt
, mflags
| MS_RDONLY
);
1236 cxt
->flags
|= MNT_FL_FORCED_RDONLY
;
1240 if (!mnt_context_switch_ns(cxt
, ns_old
))
1241 return -MNT_ERR_NAMESPACE
;
1246 * mnt_context_next_mount:
1249 * @fs: returns the current filesystem
1250 * @mntrc: returns the return code from mnt_context_mount()
1251 * @ignored: returns 1 for non-matching and 2 for already mounted filesystems
1253 * This function tries to mount the next filesystem from fstab (as returned by
1254 * mnt_context_get_fstab()). See also mnt_context_set_fstab().
1256 * You can filter out filesystems by:
1257 * mnt_context_set_options_pattern() to simulate mount -a -O pattern
1258 * mnt_context_set_fstype_pattern() to simulate mount -a -t pattern
1260 * If the filesystem is already mounted or does not match defined criteria,
1261 * then the mnt_context_next_mount() function returns zero, but the @ignored is
1262 * non-zero. Note that the root filesystem and filesystems with "noauto" option
1263 * are always ignored.
1265 * If mount(2) syscall or mount.type helper failed, then the
1266 * mnt_context_next_mount() function returns zero, but the @mntrc is non-zero.
1267 * Use also mnt_context_get_status() to check if the filesystem was
1268 * successfully mounted.
1270 * See mnt_context_mount() for more details about errors and warnings.
1272 * Returns: 0 on success,
1273 * <0 in case of error (!= mount(2) errors)
1274 * 1 at the end of the list.
1276 int mnt_context_next_mount(struct libmnt_context
*cxt
,
1277 struct libmnt_iter
*itr
,
1278 struct libmnt_fs
**fs
,
1282 struct libmnt_table
*fstab
, *mtab
;
1283 const char *o
, *tgt
;
1285 int rc
, mounted
= 0;
1292 if (!cxt
|| !fs
|| !itr
)
1296 cxt
->mtab
= NULL
; /* do not reset mtab */
1297 mnt_reset_context(cxt
);
1300 rc
= mnt_context_get_fstab(cxt
, &fstab
);
1304 rc
= mnt_table_next_fs(fstab
, itr
, fs
);
1306 return rc
; /* more filesystems (or error) */
1308 o
= mnt_fs_get_user_options(*fs
);
1309 tgt
= mnt_fs_get_target(*fs
);
1311 DBG(CXT
, ul_debugobj(cxt
, "next-mount: trying %s", tgt
));
1314 if (mnt_fs_is_swaparea(*fs
) ||
1316 /* ignore root filesystem */
1317 (tgt
&& (strcmp(tgt
, "/") == 0 || strcmp(tgt
, "root") == 0)) ||
1319 /* ignore noauto filesystems */
1320 (o
&& mnt_optstr_get_option(o
, "noauto", NULL
, NULL
) == 0) ||
1322 /* ignore filesystems which don't match options patterns */
1323 (cxt
->fstype_pattern
&& !mnt_fs_match_fstype(*fs
,
1324 cxt
->fstype_pattern
)) ||
1326 /* ignore filesystems which don't match type patterns */
1327 (cxt
->optstr_pattern
&& !mnt_fs_match_options(*fs
,
1328 cxt
->optstr_pattern
))) {
1331 DBG(CXT
, ul_debugobj(cxt
, "next-mount: not-match "
1332 "[fstype: %s, t-pattern: %s, options: %s, O-pattern: %s]",
1333 mnt_fs_get_fstype(*fs
),
1334 cxt
->fstype_pattern
,
1335 mnt_fs_get_options(*fs
),
1336 cxt
->optstr_pattern
));
1340 /* ignore already mounted filesystems */
1341 rc
= mnt_context_is_fs_mounted(cxt
, *fs
, &mounted
);
1350 if (mnt_context_is_fork(cxt
)) {
1351 rc
= mnt_fork_context(cxt
);
1353 return rc
; /* fork error */
1355 if (mnt_context_is_parent(cxt
)) {
1356 return 0; /* parent */
1360 /* child or non-forked */
1362 rc
= mnt_context_set_fs(cxt
, *fs
);
1365 * "-t <pattern>" is used to filter out fstab entries, but for ordinary
1366 * mount operation -t means "-t <type>". We have to zeroize the pattern
1367 * to avoid misinterpretation.
1369 pattern
= cxt
->fstype_pattern
;
1370 cxt
->fstype_pattern
= NULL
;
1372 rc
= mnt_context_mount(cxt
);
1374 cxt
->fstype_pattern
= pattern
;
1380 if (mnt_context_is_child(cxt
)) {
1381 DBG(CXT
, ul_debugobj(cxt
, "next-mount: child exit [rc=%d]", rc
));
1390 * mnt_context_next_remount:
1393 * @fs: returns the current filesystem
1394 * @mntrc: returns the return code from mnt_context_mount()
1395 * @ignored: returns 1 for non-matching
1397 * This function tries to remount the next mounted filesystem (as returned by
1398 * mnt_context_get_mtab()).
1400 * You can filter out filesystems by:
1401 * mnt_context_set_options_pattern() to simulate mount -a -O pattern
1402 * mnt_context_set_fstype_pattern() to simulate mount -a -t pattern
1404 * If the filesystem does not match defined criteria, then the
1405 * mnt_context_next_remount() function returns zero, but the @ignored is
1408 * If mount(2) syscall or mount.type helper failed, then the
1409 * mnt_context_next_mount() function returns zero, but the @mntrc is non-zero.
1410 * Use also mnt_context_get_status() to check if the filesystem was
1411 * successfully mounted.
1413 * See mnt_context_mount() for more details about errors and warnings.
1415 * Returns: 0 on success,
1416 * <0 in case of error (!= mount(2) errors)
1417 * 1 at the end of the list.
1421 int mnt_context_next_remount(struct libmnt_context
*cxt
,
1422 struct libmnt_iter
*itr
,
1423 struct libmnt_fs
**fs
,
1427 struct libmnt_context
*remount_cxt
= NULL
;
1428 struct libmnt_table
*mtab
;
1437 if (!cxt
|| !fs
|| !itr
)
1440 rc
= mnt_context_get_mtab(cxt
, &mtab
);
1444 rc
= mnt_table_next_fs(mtab
, itr
, fs
);
1446 return rc
; /* more filesystems (or error) */
1448 tgt
= mnt_fs_get_target(*fs
);
1450 DBG(CXT
, ul_debugobj(cxt
, "next-remount: trying %s", tgt
));
1452 /* ignore filesystems which don't match options patterns */
1453 if ((cxt
->fstype_pattern
&& !mnt_fs_match_fstype(*fs
,
1454 cxt
->fstype_pattern
)) ||
1456 /* ignore filesystems which don't match type patterns */
1457 (cxt
->optstr_pattern
&& !mnt_fs_match_options(*fs
,
1458 cxt
->optstr_pattern
))) {
1461 DBG(CXT
, ul_debugobj(cxt
, "next-remount: not-match "
1462 "[fstype: %s, t-pattern: %s, options: %s, O-pattern: %s]",
1463 mnt_fs_get_fstype(*fs
),
1464 cxt
->fstype_pattern
,
1465 mnt_fs_get_options(*fs
),
1466 cxt
->optstr_pattern
));
1470 /* make sure fstab is already read to avoid fstab parsing in cloned context */
1471 mnt_context_get_fstab(cxt
, NULL
);
1474 remount_cxt
= mnt_copy_context(cxt
);
1478 rc
= mnt_context_set_target(remount_cxt
, tgt
);
1481 * "-t <pattern>" is used to filter out fstab entries, but for ordinary
1482 * mount operation -t means "-t <type>". We have to zeroize the pattern
1483 * to avoid misinterpretation.
1485 remount_cxt
->fstype_pattern
= NULL
;
1486 rc
= mnt_context_mount(remount_cxt
);
1492 mnt_free_context(remount_cxt
);
1497 * Returns 1 if @dir parent is shared
1499 static int is_shared_tree(struct libmnt_context
*cxt
, const char *dir
)
1501 struct libmnt_table
*tb
= NULL
;
1502 struct libmnt_fs
*fs
;
1503 unsigned long mflags
= 0;
1504 char *mnt
= NULL
, *p
;
1506 struct libmnt_ns
*ns_old
;
1508 ns_old
= mnt_context_switch_target_ns(cxt
);
1510 return -MNT_ERR_NAMESPACE
;
1514 if (mnt_context_get_mtab(cxt
, &tb
) || !tb
)
1520 p
= strrchr(mnt
, '/');
1525 fs
= mnt_table_find_mountpoint(tb
, mnt
, MNT_ITER_BACKWARD
);
1527 rc
= fs
&& mnt_fs_is_kernel(fs
)
1528 && mnt_fs_get_propagation(fs
, &mflags
) == 0
1529 && (mflags
& MS_SHARED
);
1532 if (!mnt_context_switch_ns(cxt
, ns_old
))
1533 return -MNT_ERR_NAMESPACE
;
1537 int mnt_context_get_mount_excode(
1538 struct libmnt_context
*cxt
,
1545 unsigned long uflags
= 0, mflags
= 0;
1547 int restricted
= mnt_context_is_restricted(cxt
);
1548 const char *tgt
= mnt_context_get_target(cxt
);
1549 const char *src
= mnt_context_get_source(cxt
);
1551 if (mnt_context_helper_executed(cxt
)) {
1553 * /sbin/mount.<type> called, return status
1555 if (rc
== -MNT_ERR_APPLYFLAGS
&& buf
)
1556 snprintf(buf
, bufsz
, _("WARNING: failed to apply propagation flags"));
1558 return mnt_context_get_helper_status(cxt
);
1561 if (rc
== 0 && mnt_context_get_status(cxt
) == 1) {
1563 * Libmount success && syscall success.
1565 if (buf
&& mnt_context_forced_rdonly(cxt
))
1566 snprintf(buf
, bufsz
, _("WARNING: device write-protected, mounted read-only"));
1567 return MNT_EX_SUCCESS
;
1570 mnt_context_get_mflags(cxt
, &mflags
); /* mount(2) flags */
1571 mnt_context_get_user_mflags(cxt
, &uflags
); /* userspace flags */
1573 if (!mnt_context_syscall_called(cxt
)) {
1575 * libmount errors (extra library checks)
1580 snprintf(buf
, bufsz
, _("operation permitted for root only"));
1581 return MNT_EX_USAGE
;
1584 snprintf(buf
, bufsz
, _("%s is already mounted"), src
);
1585 return MNT_EX_USAGE
;
1586 case -MNT_ERR_NOFSTAB
:
1588 return MNT_EX_USAGE
;
1589 if (mnt_context_is_swapmatch(cxt
))
1590 snprintf(buf
, bufsz
, _("can't find in %s"),
1591 mnt_get_fstab_path());
1593 snprintf(buf
, bufsz
, _("can't find mount point in %s"),
1594 mnt_get_fstab_path());
1596 snprintf(buf
, bufsz
, _("can't find mount source %s in %s"),
1597 src
, mnt_get_fstab_path());
1598 return MNT_EX_USAGE
;
1599 case -MNT_ERR_AMBIFS
:
1601 snprintf(buf
, bufsz
, _("more filesystems detected on %s; use -t <type> or wipefs(8)"), src
);
1602 return MNT_EX_USAGE
;
1603 case -MNT_ERR_NOFSTYPE
:
1605 snprintf(buf
, bufsz
, restricted
?
1606 _("failed to determine filesystem type") :
1607 _("no filesystem type specified"));
1608 return MNT_EX_USAGE
;
1609 case -MNT_ERR_NOSOURCE
:
1610 if (uflags
& MNT_MS_NOFAIL
)
1611 return MNT_EX_SUCCESS
;
1614 snprintf(buf
, bufsz
, _("can't find %s"), src
);
1616 snprintf(buf
, bufsz
, _("no mount source specified"));
1618 return MNT_EX_USAGE
;
1619 case -MNT_ERR_MOUNTOPT
:
1621 snprintf(buf
, bufsz
, errno
?
1622 _("failed to parse mount options: %m") :
1623 _("failed to parse mount options"));
1624 return MNT_EX_USAGE
;
1625 case -MNT_ERR_LOOPDEV
:
1627 snprintf(buf
, bufsz
, _("failed to setup loop device for %s"), src
);
1629 case -MNT_ERR_LOOPOVERLAP
:
1631 snprintf(buf
, bufsz
, _("overlapping loop device exists for %s"), src
);
1635 snprintf(buf
, bufsz
, _("locking failed"));
1636 return MNT_EX_FILEIO
;
1637 case -MNT_ERR_NAMESPACE
:
1639 snprintf(buf
, bufsz
, _("failed to switch namespace"));
1640 return MNT_EX_SYSERR
;
1642 return mnt_context_get_generic_excode(rc
, buf
, bufsz
, _("mount failed: %m"));
1645 } else if (mnt_context_get_syscall_errno(cxt
) == 0) {
1647 * mount(2) syscall success, but something else failed
1648 * (probably error in mtab processing).
1650 if (rc
== -MNT_ERR_LOCK
) {
1652 snprintf(buf
, bufsz
, _("filesystem was mounted, but failed to update userspace mount table"));
1653 return MNT_EX_FILEIO
;
1654 } else if (rc
== -MNT_ERR_NAMESPACE
) {
1656 snprintf(buf
, bufsz
, _("filesystem was mounted, but failed to switch namespace back"));
1657 return MNT_EX_SYSERR
;
1660 return mnt_context_get_generic_excode(rc
, buf
, bufsz
,
1661 _("filesystem was mounted, but any subsequent operation failed: %m"));
1663 return MNT_EX_SOFTWARE
; /* internal error */
1670 syserr
= mnt_context_get_syscall_errno(cxt
);
1677 if (geteuid() == 0) {
1678 if (stat(tgt
, &st
) || !S_ISDIR(st
.st_mode
))
1679 snprintf(buf
, bufsz
, _("mount point is not a directory"));
1681 snprintf(buf
, bufsz
, _("permission denied"));
1683 snprintf(buf
, bufsz
, _("must be superuser to use mount"));
1688 struct libmnt_table
*tb
;
1692 if (mflags
& MS_REMOUNT
) {
1693 snprintf(buf
, bufsz
, _("mount point is busy"));
1696 if (src
&& mnt_context_get_mtab(cxt
, &tb
) == 0) {
1697 struct libmnt_iter itr
;
1698 struct libmnt_fs
*fs
;
1700 mnt_reset_iter(&itr
, MNT_ITER_FORWARD
);
1701 while (mnt_table_next_fs(tb
, &itr
, &fs
) == 0) {
1702 const char *s
= mnt_fs_get_srcpath(fs
),
1703 *t
= mnt_fs_get_target(fs
);
1705 if (t
&& s
&& mnt_fs_streq_srcpath(fs
, src
)) {
1706 snprintf(buf
, bufsz
, _("%s already mounted on %s"), s
, t
);
1712 snprintf(buf
, bufsz
, _("%s already mounted or mount point busy"), src
);
1716 if (tgt
&& lstat(tgt
, &st
)) {
1718 snprintf(buf
, bufsz
, _("mount point does not exist"));
1719 } else if (tgt
&& stat(tgt
, &st
)) {
1721 snprintf(buf
, bufsz
, _("mount point is a symbolic link to nowhere"));
1722 } else if (src
&& stat(src
, &st
)) {
1723 if (uflags
& MNT_MS_NOFAIL
)
1724 return MNT_EX_SUCCESS
;
1726 snprintf(buf
, bufsz
, _("special device %s does not exist"), src
);
1729 snprintf(buf
, bufsz
, _("mount(2) system call failed: %m"));
1734 if (stat(tgt
, &st
) || ! S_ISDIR(st
.st_mode
)) {
1736 snprintf(buf
, bufsz
, _("mount point is not a directory"));
1737 } else if (src
&& stat(src
, &st
) && errno
== ENOTDIR
) {
1738 if (uflags
& MNT_MS_NOFAIL
)
1739 return MNT_EX_SUCCESS
;
1741 snprintf(buf
, bufsz
, _("special device %s does not exist "
1742 "(a path prefix is not a directory)"), src
);
1745 snprintf(buf
, bufsz
, _("mount(2) system call failed: %m"));
1752 if (mflags
& MS_REMOUNT
)
1753 snprintf(buf
, bufsz
, _("mount point not mounted or bad option"));
1754 else if (rc
== -MNT_ERR_APPLYFLAGS
)
1755 snprintf(buf
, bufsz
, _("not mount point or bad option"));
1756 else if ((mflags
& MS_MOVE
) && is_shared_tree(cxt
, src
))
1757 snprintf(buf
, bufsz
,
1758 _("bad option; moving a mount "
1759 "residing under a shared mount is unsupported"));
1760 else if (mnt_fs_is_netfs(mnt_context_get_fs(cxt
)))
1761 snprintf(buf
, bufsz
,
1762 _("bad option; for several filesystems (e.g. nfs, cifs) "
1763 "you might need a /sbin/mount.<type> helper program"));
1765 snprintf(buf
, bufsz
,
1766 _("wrong fs type, bad option, bad superblock on %s, "
1767 "missing codepage or helper program, or other error"),
1773 snprintf(buf
, bufsz
, _("mount table full"));
1778 snprintf(buf
, bufsz
, _("can't read superblock on %s"), src
);
1784 if (mnt_context_get_fstype(cxt
))
1785 snprintf(buf
, bufsz
, _("unknown filesystem type '%s'"),
1786 mnt_context_get_fstype(cxt
));
1788 snprintf(buf
, bufsz
, _("unknown filesystem type"));
1792 if (uflags
& MNT_MS_NOFAIL
)
1793 return MNT_EX_SUCCESS
;
1796 if (src
&& stat(src
, &st
))
1797 snprintf(buf
, bufsz
, _("%s is not a block device, and stat(2) fails?"), src
);
1798 else if (src
&& S_ISBLK(st
.st_mode
))
1799 snprintf(buf
, bufsz
,
1800 _("the kernel does not recognize %s as a block device; "
1801 "maybe \"modprobe driver\" is necessary"), src
);
1802 else if (src
&& S_ISREG(st
.st_mode
))
1803 snprintf(buf
, bufsz
, _("%s is not a block device; try \"-o loop\""), src
);
1805 snprintf(buf
, bufsz
, _("%s is not a block device"), src
);
1809 if (uflags
& MNT_MS_NOFAIL
)
1810 return MNT_EX_SUCCESS
;
1812 snprintf(buf
, bufsz
, _("%s is not a valid block device"), src
);
1819 if (mflags
& MS_RDONLY
)
1820 snprintf(buf
, bufsz
, _("cannot mount %s read-only"), src
);
1821 else if (mnt_context_is_rwonly_mount(cxt
))
1822 snprintf(buf
, bufsz
, _("%s is write-protected but explicit read-write mode requested"), src
);
1823 else if (mflags
& MS_REMOUNT
)
1824 snprintf(buf
, bufsz
, _("cannot remount %s read-write, is write-protected"), src
);
1825 else if (mflags
& MS_BIND
)
1826 snprintf(buf
, bufsz
, _("bind %s failed"), src
);
1829 snprintf(buf
, bufsz
, _("mount(2) system call failed: %m"));
1834 if (uflags
& MNT_MS_NOFAIL
)
1835 return MNT_EX_SUCCESS
;
1837 snprintf(buf
, bufsz
, _("no medium found on %s"), src
);
1841 /* Bad CRC for classic filesystems (e.g. extN or XFS) */
1842 if (buf
&& src
&& stat(src
, &st
) == 0
1843 && (S_ISBLK(st
.st_mode
) || S_ISREG(st
.st_mode
))) {
1844 snprintf(buf
, bufsz
, _("cannot mount; probably corrupted filesystem on %s"), src
);
1852 snprintf(buf
, bufsz
, _("mount(2) system call failed: %m"));