2 * mount(8) -- mount a filesystem
4 * Copyright (C) 2011 Red Hat, Inc. All rights reserved.
5 * Written by Karel Zak <kzak@redhat.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it would be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include <sys/types.h>
40 #include "exitcodes.h"
44 * --guess-fstype is unsupported
46 * --options-mode={ignore,append,prepend,replace} MNT_OMODE_{IGNORE, ...}
47 * --options-source={fstab,mtab,disable} MNT_OMODE_{FSTAB,MTAB,NOTAB}
48 * --options-source-force MNT_OMODE_FORCE
51 static int passfd
= -1;
54 static int mk_exit_code(struct libmnt_context
*cxt
, int rc
);
56 static void __attribute__((__noreturn__
)) exit_non_root(const char *option
)
58 const uid_t ruid
= getuid();
59 const uid_t euid
= geteuid();
61 if (ruid
== 0 && euid
!= 0) {
62 /* user is root, but setuid to non-root */
64 errx(MOUNT_EX_USAGE
, _("only root can use \"--%s\" option "
65 "(effective UID is %u)"),
67 errx(MOUNT_EX_USAGE
, _("only root can do that "
68 "(effective UID is %u)"), euid
);
71 errx(MOUNT_EX_USAGE
, _("only root can use \"--%s\" option"), option
);
72 errx(MOUNT_EX_USAGE
, _("only root can do that"));
75 static void __attribute__((__noreturn__
)) print_version(void)
77 const char *ver
= NULL
;
78 const char **features
= NULL
, **p
;
80 mnt_get_library_version(&ver
);
81 mnt_get_library_features(&features
);
83 printf(_("%s from %s (libmount %s"),
84 program_invocation_short_name
,
89 fputs(p
== features
? ": " : ", ", stdout
);
93 exit(MOUNT_EX_SUCCESS
);
96 static int table_parser_errcb(struct libmnt_table
*tb
__attribute__((__unused__
)),
97 const char *filename
, int line
)
100 warnx(_("%s: parse error: ignore entry at line %d."),
105 static char *encrypt_pass_get(struct libmnt_context
*cxt
)
111 if (mlockall(MCL_CURRENT
| MCL_FUTURE
)) {
112 warn(_("couldn't lock into memory"));
116 return xgetpass(passfd
, _("Password: "));
119 static void encrypt_pass_release(struct libmnt_context
*cxt
120 __attribute__((__unused__
)), char *pwd
)
131 static void print_all(struct libmnt_context
*cxt
, char *pattern
, int show_label
)
133 struct libmnt_table
*tb
;
134 struct libmnt_iter
*itr
= NULL
;
135 struct libmnt_fs
*fs
;
136 struct libmnt_cache
*cache
= NULL
;
138 if (mnt_context_get_mtab(cxt
, &tb
))
139 err(MOUNT_EX_SYSERR
, _("failed to read mtab"));
141 itr
= mnt_new_iter(MNT_ITER_FORWARD
);
143 err(MOUNT_EX_SYSERR
, _("failed to initialize libmount iterator"));
145 cache
= mnt_new_cache();
147 while (mnt_table_next_fs(tb
, itr
, &fs
) == 0) {
148 const char *type
= mnt_fs_get_fstype(fs
);
149 const char *src
= mnt_fs_get_source(fs
);
150 const char *optstr
= mnt_fs_get_options(fs
);
153 if (type
&& pattern
&& !mnt_match_fstype(type
, pattern
))
156 if (!mnt_fs_is_pseudofs(fs
))
157 xsrc
= mnt_pretty_path(src
, cache
);
158 printf ("%s on %s", xsrc
? xsrc
: src
, mnt_fs_get_target(fs
));
160 printf (" type %s", type
);
162 printf (" (%s)", optstr
);
163 if (show_label
&& src
) {
164 char *lb
= mnt_cache_find_tag_value(cache
, src
, "LABEL");
166 printf (" [%s]", lb
);
172 mnt_free_cache(cache
);
179 static int mount_all(struct libmnt_context
*cxt
)
181 struct libmnt_iter
*itr
;
182 struct libmnt_fs
*fs
;
183 int mntrc
, ignored
, rc
= MOUNT_EX_SUCCESS
;
185 itr
= mnt_new_iter(MNT_ITER_FORWARD
);
187 warn(_("failed to initialize libmount iterator"));
188 return MOUNT_EX_SYSERR
;
191 while (mnt_context_next_mount(cxt
, itr
, &fs
, &mntrc
, &ignored
) == 0) {
193 const char *tgt
= mnt_fs_get_target(fs
);
196 if (mnt_context_is_verbose(cxt
))
197 printf(ignored
== 1 ? _("%-25s: ignored\n") :
198 _("%-25s: already mounted\n"),
201 } else if (mnt_context_is_fork(cxt
)) {
202 if (mnt_context_is_verbose(cxt
))
203 printf("%-25s: mount successfully forked\n", tgt
);
205 rc
|= mk_exit_code(cxt
, mntrc
);
207 if (mnt_context_get_status(cxt
)) {
208 rc
|= MOUNT_EX_SOMEOK
;
210 if (mnt_context_is_verbose(cxt
))
211 printf("%-25s: successfully mounted\n", tgt
);
216 if (mnt_context_is_parent(cxt
)) {
217 /* wait for mount --fork children */
218 int nerrs
= 0, nchildren
= 0;
220 rc
= mnt_context_wait_for_children(cxt
, &nchildren
, &nerrs
);
221 if (!rc
&& nchildren
)
222 rc
= nchildren
== nerrs
? MOUNT_EX_FAIL
: MOUNT_EX_SOMEOK
;
230 * Handles generic errors like ENOMEM, ...
233 * <0 error (usually -errno)
235 * Returns exit status (MOUNT_EX_*) and prints error message.
237 static int handle_generic_errors(int rc
, const char *msg
, ...)
252 rc
= MOUNT_EX_SYSERR
;
263 #if defined(HAVE_LIBSELINUX) && defined(HAVE_SECURITY_GET_INITIAL_CONTEXT)
264 #include <selinux/selinux.h>
265 #include <selinux/context.h>
267 static void selinux_warning(struct libmnt_context
*cxt
, const char *tgt
)
270 if (tgt
&& mnt_context_is_verbose(cxt
) && is_selinux_enabled() > 0) {
271 security_context_t raw
= NULL
, def
= NULL
;
273 if (getfilecon(tgt
, &raw
) > 0
274 && security_get_initial_context("file", &def
) == 0) {
276 if (!selinux_file_context_cmp(raw
, def
))
278 "mount: %s does not contain SELinux labels.\n"
279 " You just mounted an file system that supports labels which does not\n"
280 " contain labels, onto an SELinux box. It is likely that confined\n"
281 " applications will generate AVC messages and not be allowed access to\n"
282 " this file system. For more details see restorecon(8) and mount(8).\n"),
290 # define selinux_warning(_x, _y)
296 * <0 error (usually -errno or -1)
298 * Returns exit status (MOUNT_EX_*) and/or prints error message.
300 static int mk_exit_code(struct libmnt_context
*cxt
, int rc
)
304 unsigned long uflags
= 0, mflags
= 0;
306 int restricted
= mnt_context_is_restricted(cxt
);
307 const char *tgt
= mnt_context_get_target(cxt
);
308 const char *src
= mnt_context_get_source(cxt
);
311 if (mnt_context_helper_executed(cxt
))
313 * /sbin/mount.<type> called, return status
315 return mnt_context_get_helper_status(cxt
);
317 if (rc
== 0 && mnt_context_get_status(cxt
) == 1) {
319 * Libmount success && syscall success.
321 selinux_warning(cxt
, tgt
);
323 return MOUNT_EX_SUCCESS
; /* mount(2) success */
326 if (!mnt_context_syscall_called(cxt
)) {
328 * libmount errors (extra library checks)
332 warnx(_("only root can mount %s on %s"), src
, tgt
);
333 return MOUNT_EX_USAGE
;
335 warnx(_("%s is already mounted"), src
);
336 return MOUNT_EX_USAGE
;
339 if (src
== NULL
|| tgt
== NULL
) {
340 if (mflags
& MS_REMOUNT
)
341 warnx(_("%s not mounted"), src
? src
: tgt
);
343 warnx(_("can't find %s in %s"), src
? src
: tgt
,
344 mnt_get_fstab_path());
345 return MOUNT_EX_USAGE
;
348 if (!mnt_context_get_fstype(cxt
)) {
350 warnx(_("I could not determine the filesystem type, "
351 "and none was specified"));
353 warnx(_("you must specify the filesystem type"));
354 return MOUNT_EX_USAGE
;
356 return handle_generic_errors(rc
, _("%s: mount failed"),
359 } else if (mnt_context_get_syscall_errno(cxt
) == 0) {
361 * mount(2) syscall success, but something else failed
362 * (probably error in mtab processing).
365 return handle_generic_errors(rc
,
366 _("%s: filesystem mounted, but mount(8) failed"),
369 return MOUNT_EX_SOFTWARE
; /* internal error */
376 syserr
= mnt_context_get_syscall_errno(cxt
);
378 mnt_context_get_mflags(cxt
, &mflags
); /* mount(2) flags */
379 mnt_context_get_user_mflags(cxt
, &uflags
); /* userspace flags */
383 if (geteuid() == 0) {
384 if (stat(tgt
, &st
) || !S_ISDIR(st
.st_mode
))
385 warnx(_("mount point %s is not a directory"), tgt
);
387 warnx(_("permission denied"));
389 warnx(_("must be superuser to use mount"));
394 struct libmnt_table
*tb
;
396 if (mflags
& MS_REMOUNT
) {
397 warnx(_("%s is busy"), tgt
);
401 warnx(_("%s is already mounted or %s busy"), src
, tgt
);
403 if (src
&& mnt_context_get_mtab(cxt
, &tb
) == 0) {
404 struct libmnt_iter
*itr
= mnt_new_iter(MNT_ITER_FORWARD
);
405 struct libmnt_fs
*fs
;
407 while(mnt_table_next_fs(tb
, itr
, &fs
) == 0) {
408 const char *s
= mnt_fs_get_srcpath(fs
),
409 *t
= mnt_fs_get_target(fs
);
411 if (t
&& s
&& streq_except_trailing_slash(s
, src
))
413 " %s is already mounted on %s\n"), s
, t
);
421 warnx(_("mount point %s does not exist"), tgt
);
422 else if (stat(tgt
, &st
))
423 warnx(_("mount point %s is a symbolic link to nowhere"), tgt
);
424 else if (stat(src
, &st
)) {
425 if (uflags
& MNT_MS_NOFAIL
)
426 return MOUNT_EX_SUCCESS
;
428 warnx(_("special device %s does not exist"), src
);
431 warn(_("mount(2) failed")); /* print errno */
436 if (stat(tgt
, &st
) || ! S_ISDIR(st
.st_mode
))
437 warnx(_("mount point %s is not a directory"), tgt
);
438 else if (stat(src
, &st
) && errno
== ENOTDIR
) {
439 if (uflags
& MNT_MS_NOFAIL
)
440 return MOUNT_EX_SUCCESS
;
442 warnx(_("special device %s does not exist "
443 "(a path prefix is not a directory)"), src
);
446 warn(_("mount(2) failed")); /* print errno */
451 if (mflags
& MS_REMOUNT
)
452 warnx(_("%s not mounted or bad option"), tgt
);
454 warnx(_("wrong fs type, bad option, bad superblock on %s,\n"
455 " missing codepage or helper program, or other error"),
458 if (mnt_fs_is_netfs(mnt_context_get_fs(cxt
)))
460 " (for several filesystems (e.g. nfs, cifs) you might\n"
461 " need a /sbin/mount.<type> helper program)\n"));
464 " In some cases useful info is found in syslog - try\n"
465 " dmesg | tail or so\n"));
469 warnx(_("mount table full"));
473 warnx(_("%s: can't read superblock"), src
);
477 warnx(_("unknown filesystem type '%s'"), mnt_context_get_fstype(cxt
));
481 if (uflags
& MNT_MS_NOFAIL
)
482 return MOUNT_EX_SUCCESS
;
485 warnx(_("%s is not a block device, and stat(2) fails?"), src
);
486 else if (S_ISBLK(st
.st_mode
))
487 warnx(_("the kernel does not recognize %s as a block device\n"
488 " (maybe `modprobe driver'?)"), src
);
489 else if (S_ISREG(st
.st_mode
))
490 warnx(_("%s is not a block device (maybe try `-o loop'?)"), src
);
492 warnx(_(" %s is not a block device"), src
);
496 if (uflags
& MNT_MS_NOFAIL
)
497 return MOUNT_EX_SUCCESS
;
499 warnx(_("%s is not a valid block device"), src
);
504 if (mflags
& MS_RDONLY
)
505 warnx(_("cannot mount %s read-only"), src
);
508 warnx(_("%s is write-protected but explicit `-w' flag given"), src
);
510 else if (mflags
& MS_REMOUNT
)
511 warnx(_("cannot remount %s read-write, is write-protected"), src
);
514 warnx(_("%s is write-protected, mounting read-only"), src
);
516 mnt_context_reset_status(cxt
);
517 mnt_context_set_mflags(cxt
, mflags
| MS_RDONLY
);
518 rc
= mnt_context_do_mount(cxt
);
520 rc
= mnt_context_finalize_mount(cxt
);
527 warnx(_("no medium found on %s"), src
);
531 warn(_("mount %s on %s failed"), src
, tgt
);
535 return MOUNT_EX_FAIL
;
538 static struct libmnt_table
*append_fstab(struct libmnt_context
*cxt
,
539 struct libmnt_table
*fstab
,
544 fstab
= mnt_new_table();
546 err(MOUNT_EX_SYSERR
, _("failed to initialize libmount table"));
548 mnt_table_set_parser_errcb(fstab
, table_parser_errcb
);
549 mnt_context_set_fstab(cxt
, fstab
);
552 if (mnt_table_parse_fstab(fstab
, path
))
553 errx(MOUNT_EX_USAGE
,_("%s: failed to parse"), path
);
558 static void __attribute__((__noreturn__
)) usage(FILE *out
)
560 fputs(USAGE_HEADER
, out
);
563 " %1$s -a [options]\n"
564 " %1$s [options] <source> | <directory>\n"
565 " %1$s [options] <source> <directory>\n"
566 " %1$s <operation> <mountpoint> [<target>]\n"),
567 program_invocation_short_name
);
569 fputs(USAGE_OPTIONS
, out
);
571 " -a, --all mount all filesystems mentioned in fstab\n"
572 " -c, --no-canonicalize don't canonicalize paths\n"
573 " -f, --fake dry run; skip the mount(2) syscall\n"
574 " -F, --fork fork off for each device (use with -a)\n"
575 " -T, --fstab <path> alternative file to /etc/fstab\n"));
577 " -h, --help display this help text and exit\n"
578 " -i, --internal-only don't call the mount.<type> helpers\n"
579 " -l, --show-labels lists all mounts with LABELs\n"
580 " -n, --no-mtab don't write to /etc/mtab\n"));
582 " -o, --options <list> comma-separated list of mount options\n"
583 " -O, --test-opts <list> limit the set of filesystems (use with -a)\n"
584 " -p, --pass-fd <num> read the passphrase from file descriptor\n"
585 " -r, --read-only mount the filesystem read-only (same as -o ro)\n"
586 " -t, --types <list> limit the set of filesystem types\n"));
588 " -v, --verbose say what is being done\n"
589 " -V, --version display version information and exit\n"
590 " -w, --read-write mount the filesystem read-write (default)\n"));
592 fputs(USAGE_SEPARATOR
, out
);
593 fputs(USAGE_HELP
, out
);
594 fputs(USAGE_VERSION
, out
);
598 " -L, --label <label> synonym for LABEL=<label>\n"
599 " -U, --uuid <uuid> synonym for UUID=<uuid>\n"
600 " LABEL=<label> specifies device by filesystem label\n"
601 " UUID=<uuid> specifies device by filesystem UUID\n"));
603 " <device> specifies device by path\n"
604 " <directory> mountpoint for bind mounts (see --bind/rbind)\n"
605 " <file> regular file for loopdev setup\n"));
609 " -B, --bind mount a subtree somewhere else (same as -o bind)\n"
610 " -M, --move move a subtree to some other place\n"
611 " -R, --rbind mount a subtree and all submounts somewhere else\n"));
613 " --make-shared mark a subtree as shared\n"
614 " --make-slave mark a subtree as slave\n"
615 " --make-private mark a subtree as private\n"
616 " --make-unbindable mark a subtree as unbindable\n"));
618 " --make-rshared recursively mark a whole subtree as shared\n"
619 " --make-rslave recursively mark a whole subtree as slave\n"
620 " --make-rprivate recursively mark a whole subtree as private\n"
621 " --make-runbindable recursively mark a whole subtree as unbindable\n"));
623 fprintf(out
, USAGE_MAN_TAIL("mount(8)"));
625 exit(out
== stderr
? MOUNT_EX_USAGE
: MOUNT_EX_SUCCESS
);
628 int main(int argc
, char **argv
)
630 int c
, rc
= MOUNT_EX_SUCCESS
, all
= 0, show_labels
= 0;
631 struct libmnt_context
*cxt
;
632 struct libmnt_table
*fstab
= NULL
;
633 char *source
= NULL
, *srcbuf
= NULL
;
635 unsigned long oper
= 0;
638 MOUNT_OPT_SHARED
= CHAR_MAX
+ 1,
641 MOUNT_OPT_UNBINDABLE
,
645 MOUNT_OPT_RUNBINDABLE
648 static const struct option longopts
[] = {
649 { "all", 0, 0, 'a' },
650 { "fake", 0, 0, 'f' },
651 { "fstab", 1, 0, 'T' },
652 { "fork", 0, 0, 'F' },
653 { "help", 0, 0, 'h' },
654 { "no-mtab", 0, 0, 'n' },
655 { "read-only", 0, 0, 'r' },
657 { "verbose", 0, 0, 'v' },
658 { "version", 0, 0, 'V' },
659 { "read-write", 0, 0, 'w' },
661 { "options", 1, 0, 'o' },
662 { "test-opts", 1, 0, 'O' },
663 { "pass-fd", 1, 0, 'p' },
664 { "types", 1, 0, 't' },
665 { "uuid", 1, 0, 'U' },
666 { "label", 1, 0, 'L'},
667 { "bind", 0, 0, 'B' },
668 { "move", 0, 0, 'M' },
669 { "rbind", 0, 0, 'R' },
670 { "make-shared", 0, 0, MOUNT_OPT_SHARED
},
671 { "make-slave", 0, 0, MOUNT_OPT_SLAVE
},
672 { "make-private", 0, 0, MOUNT_OPT_PRIVATE
},
673 { "make-unbindable", 0, 0, MOUNT_OPT_UNBINDABLE
},
674 { "make-rshared", 0, 0, MOUNT_OPT_RSHARED
},
675 { "make-rslave", 0, 0, MOUNT_OPT_RSLAVE
},
676 { "make-rprivate", 0, 0, MOUNT_OPT_RPRIVATE
},
677 { "make-runbindable", 0, 0, MOUNT_OPT_RUNBINDABLE
},
678 { "no-canonicalize", 0, 0, 'c' },
679 { "internal-only", 0, 0, 'i' },
680 { "show-labels", 0, 0, 'l' },
685 setlocale(LC_ALL
, "");
686 bindtextdomain(PACKAGE
, LOCALEDIR
);
690 cxt
= mnt_new_context();
692 err(MOUNT_EX_SYSERR
, _("libmount context allocation failed"));
694 mnt_context_set_tables_errcb(cxt
, table_parser_errcb
);
696 while ((c
= getopt_long(argc
, argv
, "aBcfFhilL:Mno:O:p:rRsU:vVwt:T:",
697 longopts
, NULL
)) != -1) {
699 /* only few options are allowed for non-root users */
700 if (mnt_context_is_restricted(cxt
) && !strchr("hlLUVvpr", c
))
701 exit_non_root(option_to_longopt(c
, longopts
));
708 mnt_context_disable_canonicalize(cxt
, TRUE
);
711 mnt_context_enable_fake(cxt
, TRUE
);
714 mnt_context_enable_fork(cxt
, TRUE
);
720 mnt_context_disable_helpers(cxt
, TRUE
);
723 mnt_context_disable_mtab(cxt
, TRUE
);
726 if (mnt_context_append_options(cxt
, "ro"))
727 err(MOUNT_EX_SYSERR
, _("failed to append options"));
731 mnt_context_enable_verbose(cxt
, TRUE
);
737 if (mnt_context_append_options(cxt
, "rw"))
738 err(MOUNT_EX_SYSERR
, _("failed to append options"));
742 if (mnt_context_append_options(cxt
, optarg
))
743 err(MOUNT_EX_SYSERR
, _("failed to append options"));
746 if (mnt_context_set_options_pattern(cxt
, optarg
))
747 err(MOUNT_EX_SYSERR
, _("failed to set options pattern"));
750 passfd
= strtol_or_err(optarg
,
751 _("invalid passphrase file descriptor"));
756 errx(MOUNT_EX_USAGE
, _("only one <source> may be specified"));
757 if (asprintf(&srcbuf
, "%s=\"%s\"",
758 c
== 'L' ? "LABEL" : "UUID", optarg
) <= 0)
759 err(MOUNT_EX_SYSERR
, _("failed to allocate source buffer"));
769 fstab
= append_fstab(cxt
, fstab
, optarg
);
772 mnt_context_enable_sloppy(cxt
, TRUE
);
781 oper
= (MS_BIND
| MS_REC
);
783 case MOUNT_OPT_SHARED
:
786 case MOUNT_OPT_SLAVE
:
789 case MOUNT_OPT_PRIVATE
:
792 case MOUNT_OPT_UNBINDABLE
:
793 oper
= MS_UNBINDABLE
;
795 case MOUNT_OPT_RSHARED
:
796 oper
= (MS_SHARED
| MS_REC
);
798 case MOUNT_OPT_RSLAVE
:
799 oper
= (MS_SLAVE
| MS_REC
);
801 case MOUNT_OPT_RPRIVATE
:
802 oper
= (MS_PRIVATE
| MS_REC
);
804 case MOUNT_OPT_RUNBINDABLE
:
805 oper
= (MS_UNBINDABLE
| MS_REC
);
816 if (!source
&& !argc
&& !all
) {
819 print_all(cxt
, types
, show_labels
);
823 if (oper
&& (types
|| all
|| source
))
826 if (types
&& (all
|| strchr(types
, ',') ||
827 strncmp(types
, "no", 2) == 0))
828 mnt_context_set_fstype_pattern(cxt
, types
);
830 mnt_context_set_fstype(cxt
, types
);
832 mnt_context_set_passwd_cb(cxt
, encrypt_pass_get
, encrypt_pass_release
);
841 } else if (argc
== 0 && source
) {
845 mnt_context_set_source(cxt
, source
);
847 } else if (argc
== 1) {
849 * C) mount [-L|-U] <target>
850 * mount <source|target>
853 if (mnt_context_is_restricted(cxt
))
855 mnt_context_set_source(cxt
, source
);
857 mnt_context_set_target(cxt
, argv
[0]);
859 } else if (argc
== 2 && !source
) {
861 * D) mount <source> <target>
863 if (mnt_context_is_restricted(cxt
))
865 mnt_context_set_source(cxt
, argv
[0]);
866 mnt_context_set_target(cxt
, argv
[1]);
871 /* MS_PROPAGATION operations, let's set the mount flags */
872 mnt_context_set_mflags(cxt
, oper
);
874 /* For -make* or --bind is fstab unnecessary */
875 mnt_context_set_optsmode(cxt
, MNT_OMODE_NOTAB
);
878 rc
= mnt_context_mount(cxt
);
879 rc
= mk_exit_code(cxt
, rc
);
883 mnt_free_context(cxt
);
884 mnt_free_table(fstab
);