2 * A mount(8) for Linux.
4 * Modifications by many people. Distributed under GPL.
17 #include <sys/types.h>
18 #include <sys/ioctl.h>
21 #include <sys/mount.h>
25 #ifdef HAVE_LIBSELINUX
26 #include <selinux/selinux.h>
27 #include <selinux/context.h>
30 #include "pathnames.h"
33 #include "mount_constants.h"
36 #include "mount_mntent.h"
40 #include "getusername.h"
45 #define DO_PS_FIDDLING
48 #include "setproctitle.h"
51 /* True for fake mount (-f). */
54 /* True if we are allowed to call /sbin/mount.${FSTYPE} */
55 static int external_allowed = 1;
57 /* Don't write an entry in /etc/mtab (-n). */
58 static int nomtab = 0;
60 /* True for explicit readonly (-r). */
61 static int readonly = 0;
63 /* Nonzero for sloppy (-s). */
64 static int sloppy = 0;
66 /* True for explicit read/write (-w). */
67 static int readwrite = 0;
69 /* True for all mount (-a). */
70 static int mount_all = 0;
72 /* True for fork() during all mount (-F). */
73 static int optfork = 0;
75 /* Add volumelabel in a listing of mounted devices (-l). */
76 static int list_with_volumelabel = 0;
78 /* Nonzero for mount {bind|move|make-shared|make-private|
79 * make-unbindable|make-slave}
81 static int mounttype = 0;
83 /* True if (ruid != euid) or (0 != ruid), i.e. only "user" mounts permitted. */
84 static int restricted = 1;
86 /* Contains the fd to read the passphrase from, if any. */
89 /* mount(2) options */
98 /* Map from -o and fstab option strings to the flag argument to mount(2). */
100 const char *opt; /* option name */
101 int skip; /* skip in mtab option string */
102 int inv; /* true if flag value should be inverted */
103 int mask; /* flag mask value */
106 /* Custom mount options for our own purposes. */
107 /* Maybe these should now be freed for kernel use again */
108 #define MS_NOAUTO 0x80000000
109 #define MS_USERS 0x40000000
110 #define MS_USER 0x20000000
111 #define MS_OWNER 0x10000000
112 #define MS_GROUP 0x08000000
113 #define MS_COMMENT 0x02000000
114 #define MS_LOOP 0x00010000
116 /* Options that we keep the mount system call from seeing. */
117 #define MS_NOSYS (MS_NOAUTO|MS_USERS|MS_USER|MS_COMMENT|MS_LOOP)
119 /* Options that we keep from appearing in the options field in the mtab. */
120 #define MS_NOMTAB (MS_REMOUNT|MS_NOAUTO|MS_USERS|MS_USER)
122 #define MS_PROPAGATION (MS_SHARED|MS_SLAVE|MS_UNBINDABLE|MS_PRIVATE)
124 /* Options that we make ordinary users have by default. */
125 #define MS_SECURE (MS_NOEXEC|MS_NOSUID|MS_NODEV)
127 /* Options that we make owner-mounted devices have by default */
128 #define MS_OWNERSECURE (MS_NOSUID|MS_NODEV)
130 static const struct opt_map opt_map[] = {
131 { "defaults", 0, 0, 0 }, /* default options */
132 { "ro", 1, 0, MS_RDONLY }, /* read-only */
133 { "rw", 1, 1, MS_RDONLY }, /* read-write */
134 { "exec", 0, 1, MS_NOEXEC }, /* permit execution of binaries */
135 { "noexec", 0, 0, MS_NOEXEC }, /* don't execute binaries */
136 { "suid", 0, 1, MS_NOSUID }, /* honor suid executables */
137 { "nosuid", 0, 0, MS_NOSUID }, /* don't honor suid executables */
138 { "dev", 0, 1, MS_NODEV }, /* interpret device files */
139 { "nodev", 0, 0, MS_NODEV }, /* don't interpret devices */
140 { "sync", 0, 0, MS_SYNCHRONOUS}, /* synchronous I/O */
141 { "async", 0, 1, MS_SYNCHRONOUS}, /* asynchronous I/O */
142 { "dirsync", 0, 0, MS_DIRSYNC}, /* synchronous directory modifications */
143 { "remount", 0, 0, MS_REMOUNT}, /* Alter flags of mounted FS */
144 { "bind", 0, 0, MS_BIND }, /* Remount part of tree elsewhere */
145 { "rbind", 0, 0, MS_BIND|MS_REC }, /* Idem, plus mounted subtrees */
146 { "auto", 0, 1, MS_NOAUTO }, /* Can be mounted using -a */
147 { "noauto", 0, 0, MS_NOAUTO }, /* Can only be mounted explicitly */
148 { "users", 0, 0, MS_USERS }, /* Allow ordinary user to mount */
149 { "nousers", 0, 1, MS_USERS }, /* Forbid ordinary user to mount */
150 { "user", 0, 0, MS_USER }, /* Allow ordinary user to mount */
151 { "nouser", 0, 1, MS_USER }, /* Forbid ordinary user to mount */
152 { "owner", 0, 0, MS_OWNER }, /* Let the owner of the device mount */
153 { "noowner", 0, 1, MS_OWNER }, /* Device owner has no special privs */
154 { "group", 0, 0, MS_GROUP }, /* Let the group of the device mount */
155 { "nogroup", 0, 1, MS_GROUP }, /* Device group has no special privs */
156 { "_netdev", 0, 0, MS_COMMENT}, /* Device requires network */
157 { "comment", 0, 0, MS_COMMENT}, /* fstab comment only (kudzu,_netdev)*/
159 /* add new options here */
161 { "sub", 0, 1, MS_NOSUB }, /* allow submounts */
162 { "nosub", 0, 0, MS_NOSUB }, /* don't allow submounts */
165 { "quiet", 0, 0, MS_SILENT }, /* be quiet */
166 { "loud", 0, 1, MS_SILENT }, /* print out messages. */
169 { "mand", 0, 0, MS_MANDLOCK }, /* Allow mandatory locks on this FS */
170 { "nomand", 0, 1, MS_MANDLOCK }, /* Forbid mandatory locks on this FS */
172 { "loop", 1, 0, MS_LOOP }, /* use a loop device */
174 { "atime", 0, 1, MS_NOATIME }, /* Update access time */
175 { "noatime", 0, 0, MS_NOATIME }, /* Do not update access time */
178 { "iversion", 0, 0, MS_I_VERSION }, /* Update inode I_version time */
179 { "noiversion", 0, 1, MS_I_VERSION }, /* Don't update inode I_version time */
182 { "diratime", 0, 1, MS_NODIRATIME }, /* Update dir access times */
183 { "nodiratime", 0, 0, MS_NODIRATIME },/* Do not update dir access times */
186 { "relatime", 0, 0, MS_RELATIME }, /* Update access times relative to
188 { "norelatime", 0, 1, MS_RELATIME }, /* Update access time without regard
191 #ifdef MS_STRICTATIME
192 { "strictatime", 0, 0, MS_STRICTATIME }, /* Strict atime semantics */
193 { "nostrictatime", 0, 1, MS_STRICTATIME }, /* kernel default atime */
195 { "nofail", 0, 0, MS_COMMENT}, /* Do not fail if ENOENT on dev */
199 static int opt_nofail = 0;
201 static const char *opt_loopdev, *opt_vfstype, *opt_offset, *opt_sizelimit,
202 *opt_encryption, *opt_speed, *opt_comment, *opt_uhelper;
204 static int mounted (const char *spec0, const char *node0);
205 static int check_special_mountprog(const char *spec, const char *node,
206 const char *type, int flags, char *extra_opts, int *status);
208 static struct string_opt_map {
212 } string_opt_map[] = {
213 { "loop=", 0, &opt_loopdev },
214 { "vfs=", 1, &opt_vfstype },
215 { "offset=", 0, &opt_offset },
216 { "sizelimit=", 0, &opt_sizelimit },
217 { "encryption=", 0, &opt_encryption },
218 { "speed=", 0, &opt_speed },
219 { "comment=", 1, &opt_comment },
220 { "uhelper=", 0, &opt_uhelper },
225 clear_string_opts(void) {
226 struct string_opt_map *m;
228 for (m = &string_opt_map[0]; m->tag; m++)
233 parse_string_opt(char *s) {
234 struct string_opt_map *m;
237 for (m = &string_opt_map[0]; m->tag; m++) {
238 lth = strlen(m->tag);
239 if (!strncmp(s, m->tag, lth)) {
240 *(m->valptr) = xstrdup(s + lth);
247 /* Report on a single mount. */
249 print_one (const struct my_mntent *me) {
252 printf ("%s on %s", me->mnt_fsname, me->mnt_dir);
253 if (me->mnt_type != NULL && *(me->mnt_type) != '\0')
254 printf (" type %s", me->mnt_type);
255 if (me->mnt_opts != NULL)
256 printf (" (%s)", me->mnt_opts);
257 if (list_with_volumelabel && is_pseudo_fs(me->mnt_type) == 0) {
258 const char *devname = spec_to_devname(me->mnt_fsname);
263 label = fsprobe_get_label_by_devname(devname);
267 printf (" [%s]", label);
275 /* Report on everything in mtab (of the specified types if any). */
277 print_all (char *types) {
278 struct mntentchn *mc, *mc0;
281 for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt) {
282 if (matching_type (mc->m.mnt_type, types))
283 print_one (&(mc->m));
288 /* reallocates its first arg */
290 append_opt(char *s, const char *opt, const char *val)
296 return xstrdup(opt); /* opt */
298 return xstrconcat3(NULL, opt, val); /* opt=val */
301 return xstrconcat3(s, ",", opt); /* s,opt */
303 return xstrconcat4(s, ",", opt, val); /* s,opt=val */
307 append_numopt(char *s, const char *opt, long num)
311 snprintf(buf, sizeof(buf), "%ld", num);
312 return append_opt(s, opt, buf);
315 #ifdef HAVE_LIBSELINUX
316 /* strip quotes from a "string"
317 * Warning: This function modify the "str" argument.
320 strip_quotes(char *str)
327 end = strrchr(str, '"');
328 if (end == NULL || end == str)
329 die (EX_USAGE, _("mount: improperly quoted option string '%s'"), str);
335 /* translates SELinux context from human to raw format and
336 * appends it to the mount extra options.
338 * returns -1 on error and 0 on success
341 append_context(const char *optname, char *optdata, char **extra_opts)
343 security_context_t raw = NULL;
346 if (is_selinux_enabled() != 1)
347 /* ignore the option if we running without selinux */
350 if (optdata==NULL || *optdata=='\0' || optname==NULL)
353 /* TODO: use strip_quotes() for all mount options? */
354 data = *optdata =='"' ? strip_quotes(optdata) : optdata;
356 if (selinux_trans_to_raw_context(
357 (security_context_t) data, &raw) == -1 ||
362 printf(_("mount: translated %s '%s' to '%s'\n"),
363 optname, data, (char *) raw);
365 *extra_opts = append_opt(*extra_opts, optname, NULL);
366 *extra_opts = xstrconcat4(*extra_opts, "\"", (char *) raw, "\"");
374 * Look for OPT in opt_map table and return mask value.
375 * If OPT isn't found, tack it onto extra_opts (which is non-NULL).
376 * For the options uid= and gid= replace user or group name by its value.
379 parse_opt(char *opt, int *mask, char **extra_opts) {
380 const struct opt_map *om;
382 for (om = opt_map; om->opt != NULL; om++)
383 if (streq (opt, om->opt)) {
388 if ((om->mask == MS_USER || om->mask == MS_USERS)
391 if ((om->mask == MS_OWNER || om->mask == MS_GROUP)
393 *mask |= MS_OWNERSECURE;
395 if (om->mask == MS_SILENT && om->inv) {
400 if (streq(opt, "nofail"))
405 /* convert nonnumeric ids to numeric */
406 if (!strncmp(opt, "uid=", 4) && !isdigit(opt[4])) {
407 struct passwd *pw = getpwnam(opt+4);
410 *extra_opts = append_numopt(*extra_opts,
415 if (!strncmp(opt, "gid=", 4) && !isdigit(opt[4])) {
416 struct group *gr = getgrnam(opt+4);
419 *extra_opts = append_numopt(*extra_opts,
425 #ifdef HAVE_LIBSELINUX
426 if (strncmp(opt, "context=", 8) == 0 && *(opt+8)) {
427 if (append_context("context=", opt+8, extra_opts) == 0)
430 if (strncmp(opt, "fscontext=", 10) == 0 && *(opt+10)) {
431 if (append_context("fscontext=", opt+10, extra_opts) == 0)
434 if (strncmp(opt, "defcontext=", 11) == 0 && *(opt+11)) {
435 if (append_context("defcontext=", opt+11, extra_opts) == 0)
438 if (strncmp(opt, "rootcontext=", 12) == 0 && *(opt+12)) {
439 if (append_context("rootcontext=", opt+12, extra_opts) == 0)
443 *extra_opts = append_opt(*extra_opts, opt, NULL);
446 /* Take -o options list and compute 4th and 5th args to mount(2). flags
447 gets the standard options (indicated by bits) and extra_opts all the rest */
449 parse_opts (const char *options, int *flags, char **extra_opts) {
455 if (options != NULL) {
456 char *opts = xstrdup(options);
460 for (p=opts, opt=NULL; p && *p; p++) {
462 opt = p; /* begin of the option item */
464 open_quote ^= 1; /* reverse the status */
466 continue; /* still in quoted block */
468 *p = '\0'; /* terminate the option item */
469 /* end of option item or last item */
470 if (*p == '\0' || *(p+1) == '\0') {
471 if (!parse_string_opt(opt))
472 parse_opt(opt, flags, extra_opts);
482 *flags &= ~MS_RDONLY;
484 if (mounttype & MS_PROPAGATION)
489 /* Try to build a canonical options string. */
491 fix_opts_string (int flags, const char *extra_opts, const char *user) {
492 const struct opt_map *om;
493 const struct string_opt_map *m;
496 new_opts = append_opt(NULL, (flags & MS_RDONLY) ? "ro" : "rw", NULL);
497 for (om = opt_map; om->opt != NULL; om++) {
500 if (om->inv || !om->mask || (flags & om->mask) != om->mask)
502 new_opts = append_opt(new_opts, om->opt, NULL);
505 for (m = &string_opt_map[0]; m->tag; m++) {
506 if (!m->skip && *(m->valptr))
507 new_opts = append_opt(new_opts, m->tag, *(m->valptr));
509 if (extra_opts && *extra_opts)
510 new_opts = append_opt(new_opts, extra_opts, NULL);
513 new_opts = append_opt(new_opts, "user=", user);
519 already (const char *spec0, const char *node0) {
520 struct mntentchn *mc;
522 char *spec = canonicalize_spec(spec0);
523 char *node = canonicalize(node0);
525 if ((mc = getmntfile(node)) != NULL)
526 error (_("mount: according to mtab, "
527 "%s is already mounted on %s"),
528 mc->m.mnt_fsname, node);
529 else if (spec && strcmp (spec, "none") &&
530 (mc = getmntfile(spec)) != NULL)
531 error (_("mount: according to mtab, %s is mounted on %s"),
532 spec, mc->m.mnt_dir);
542 /* Create mtab with a root entry. */
545 struct mntentchn *fstab;
546 struct my_mntent mnt;
552 mfp = my_setmntent (_PATH_MOUNTED, "a+");
553 if (mfp == NULL || mfp->mntent_fp == NULL) {
555 die (EX_FILEIO, _("mount: can't open %s for writing: %s"),
556 _PATH_MOUNTED, strerror (errsv));
559 /* Find the root entry by looking it up in fstab */
560 if ((fstab = getfs_by_dir ("/")) || (fstab = getfs_by_dir ("root"))) {
562 parse_opts (fstab->m.mnt_opts, &flags, &extra_opts);
564 mnt.mnt_fsname = spec_to_devname(fstab->m.mnt_fsname);
565 mnt.mnt_type = fstab->m.mnt_type;
566 mnt.mnt_opts = fix_opts_string (flags, extra_opts, NULL);
567 mnt.mnt_freq = mnt.mnt_passno = 0;
570 if (my_addmntent (mfp, &mnt) == 1) {
572 die (EX_FILEIO, _("mount: error writing %s: %s"),
573 _PATH_MOUNTED, strerror (errsv));
576 if (fchmod (fileno (mfp->mntent_fp), 0644) < 0)
577 if (errno != EROFS) {
580 _("mount: error changing mode of %s: %s"),
581 _PATH_MOUNTED, strerror (errsv));
590 /* count successful mount system calls */
591 static int mountcount = 0;
595 * Mount a single file system. Keep track of successes.
596 * returns: 0: OK, -1: error in errno
599 do_mount_syscall (struct mountargs *args) {
600 int flags = args->flags;
602 if ((flags & MS_MGC_MSK) == 0)
606 printf("mount: mount(2) syscall: source: \"%s\", target: \"%s\", "
607 "filesystemtype: \"%s\", mountflags: %d, data: %s\n",
608 args->spec, args->node, args->type, flags, (char *) args->data);
610 return mount (args->spec, args->node, args->type, flags, args->data);
615 * Mount a single file system, possibly invoking an external handler to
616 * do so. Keep track of successes.
617 * returns: 0: OK, -1: error in errno
620 do_mount (struct mountargs *args, int *special, int *status) {
622 if (check_special_mountprog(args->spec, args->node, args->type,
623 args->flags, args->data, status)) {
627 ret = do_mount_syscall(args);
635 * check_special_mountprog()
636 * If there is a special mount program for this type, exec it.
637 * returns: 0: no exec was done, 1: exec was done, status has result
640 check_special_mountprog(const char *spec, const char *node, const char *type, int flags,
641 char *extra_opts, int *status) {
646 if (!external_allowed)
649 if (type == NULL || strcmp(type, "none") == 0)
652 if (strlen(type) < 100) {
653 sprintf(mountprog, "/sbin/mount.%s", type);
654 if (stat(mountprog, &statbuf) == 0) {
659 char *oo, *mountargs[10];
662 if(setgid(getgid()) < 0)
663 die(EX_FAIL, _("mount: cannot set group id: %s"), strerror(errno));
665 if(setuid(getuid()) < 0)
666 die(EX_FAIL, _("mount: cannot set user id: %s"), strerror(errno));
668 oo = fix_opts_string (flags, extra_opts, NULL);
669 mountargs[i++] = mountprog; /* 1 */
670 mountargs[i++] = (char *) spec; /* 2 */
671 mountargs[i++] = (char *) node; /* 3 */
672 if (sloppy && strncmp(type, "nfs", 3) == 0)
673 mountargs[i++] = "-s"; /* 4 */
675 mountargs[i++] = "-f"; /* 5 */
677 mountargs[i++] = "-n"; /* 6 */
679 mountargs[i++] = "-v"; /* 7 */
681 mountargs[i++] = "-o"; /* 8 */
682 mountargs[i++] = oo; /* 9 */
684 mountargs[i] = NULL; /* 10 */
688 while(mountargs[i]) {
689 printf("mount: external mount: argv[%d] = \"%s\"\n",
696 execv(mountprog, mountargs);
697 exit(1); /* exec failed */
698 } else if (res != -1) {
701 *status = (WIFEXITED(st) ? WEXITSTATUS(st) : EX_SYSERR);
705 error(_("mount: cannot fork: %s"), strerror(errsv));
713 /* list of already tested filesystems by procfsloop_mount() */
714 static struct tried {
720 was_tested(const char *fstype) {
723 if (fsprobe_known_fstype(fstype))
725 for (t = tried; t; t = t->next) {
726 if (!strcmp(t->type, fstype))
733 set_tested(const char *fstype) {
734 struct tried *t = xmalloc(sizeof(struct tried));
737 t->type = xstrdup(fstype);
743 struct tried *t, *tt;
756 procfsnext(FILE *procfs) {
760 while (fgets(line, sizeof(line), procfs)) {
761 if (sscanf (line, "nodev %[^\n]\n", fsname) == 1) continue;
762 if (sscanf (line, " %[^ \n]\n", fsname) != 1) continue;
763 return xstrdup(fsname);
768 /* Only use /proc/filesystems here, this is meant to test what
769 the kernel knows about, so /etc/filesystems is irrelevant.
770 Return: 1: yes, 0: no, -1: cannot open procfs */
772 known_fstype_in_procfs(const char *type)
778 procfs = fopen(_PATH_PROC_FILESYSTEMS, "r");
781 while ((fsname = procfsnext(procfs)) != NULL)
782 if (!strcmp(fsname, type)) {
792 /* Try all types in FILESYSTEMS, except those in *types,
793 in case *types starts with "no" */
794 /* return: 0: OK, -1: error in errno, 1: type not found */
795 /* when 0 or -1 is returned, *types contains the type used */
796 /* when 1 is returned, *types is NULL */
798 procfsloop_mount(int (*mount_fn)(struct mountargs *, int *, int *),
799 struct mountargs *args,
801 int *special, int *status)
803 char *files[2] = { _PATH_FILESYSTEMS, _PATH_PROC_FILESYSTEMS };
806 const char *notypes = NULL;
812 if (*types && !strncmp(*types, "no", 2)) {
814 notypes = (*types) + 2;
818 /* Use _PATH_PROC_FILESYSTEMS only when _PATH_FILESYSTEMS
819 * (/etc/filesystems) does not exist. In some cases trying a
820 * filesystem that the kernel knows about on the wrong data will crash
821 * the kernel; in such cases _PATH_FILESYSTEMS can be used to list the
822 * filesystems that we are allowed to try, and in the order they should
823 * be tried. End _PATH_FILESYSTEMS with a line containing a single '*'
824 * only, if _PATH_PROC_FILESYSTEMS should be tried afterwards.
826 for (i=0; i<2; i++) {
827 procfs = fopen(files[i], "r");
830 while ((fsname = procfsnext(procfs)) != NULL) {
831 if (!strcmp(fsname, "*")) {
835 if (was_tested (fsname))
837 if (no && matching_type(fsname, notypes))
842 printf(_("Trying %s\n"), fsname);
843 if ((*mount_fn) (args, special, status) == 0) {
847 } else if (errno != EINVAL &&
848 known_fstype_in_procfs(fsname) == 1) {
865 guess_fstype_by_devname(const char *devname)
867 const char *type = fsprobe_get_fstype_by_devname(devname);
870 printf (_("mount: you didn't specify a filesystem type for %s\n"), devname);
873 printf (_(" I will try all types mentioned in %s or %s\n"),
874 _PATH_FILESYSTEMS, _PATH_PROC_FILESYSTEMS);
875 else if (!strcmp(type, MNTTYPE_SWAP))
876 printf (_(" and it looks like this is swapspace\n"));
878 printf (_(" I will try type %s\n"), type);
884 * guess_fstype_and_mount()
885 * Mount a single file system. Guess the type when unknown.
886 * returns: 0: OK, -1: error in errno, 1: other error
887 * don't exit on non-fatal errors.
888 * on return types is filled with the type used.
891 guess_fstype_and_mount(const char *spec, const char *node, const char **types,
892 int flags, char *mount_opts, int *special, int *status) {
893 struct mountargs args = { spec, node, NULL, flags & ~MS_NOSYS, mount_opts };
895 if (*types && strcasecmp (*types, "auto") == 0)
898 if (!*types && !(flags & MS_REMOUNT)) {
899 *types = guess_fstype_by_devname(spec);
901 if (!strcmp(*types, MNTTYPE_SWAP)) {
902 error(_("%s looks like swapspace - not mounted"), spec);
907 return do_mount (&args, special, status);
912 /* Accept a comma-separated list of types, and try them one by one */
913 /* A list like "nonfs,.." indicates types not to use */
914 if (*types && strncmp(*types, "no", 2) && strchr(*types,',')) {
915 char *t = strdup(*types);
918 while((p = strchr(t,',')) != NULL) {
920 args.type = *types = t;
921 if (do_mount (&args, special, status) == 0)
925 /* do last type below */
929 if (*types || (flags & MS_REMOUNT)) {
931 return do_mount (&args, special, status);
934 return procfsloop_mount(do_mount, &args, types, special, status);
939 * Die if the user is not allowed to do this.
942 restricted_check(const char *spec, const char *node, int *flags, char **user) {
945 * MS_OWNER: Allow owners to mount when fstab contains
946 * the owner option. Note that this should never be used
947 * in a high security environment, but may be useful to give
948 * people at the console the possibility of mounting a floppy.
949 * MS_GROUP: Allow members of device group to mount. (Martin Dickopp)
951 if (*flags & (MS_OWNER | MS_GROUP)) {
954 if (!strncmp(spec, "/dev/", 5) && stat(spec, &sb) == 0) {
956 if (*flags & MS_OWNER) {
957 if (getuid() == sb.st_uid)
961 if (*flags & MS_GROUP) {
962 if (getgid() == sb.st_gid)
965 int n = getgroups(0, NULL);
968 gid_t *groups = xmalloc(n * sizeof(*groups));
969 if (getgroups(n, groups) == n) {
971 for (i = 0; i < n; i++) {
972 if (groups[i] == sb.st_gid) {
985 /* James Kehl <mkehl@gil.com.au> came with a similar patch:
986 allow an arbitrary user to mount when he is the owner of
987 the mount-point and has write-access to the device.
988 This is even less secure. Let me skip it for the time being;
989 there should be an explicit fstab line allowing such things. */
991 if (!(*flags & (MS_USER | MS_USERS))) {
992 if (already (spec, node))
993 die (EX_USAGE, _("mount failed"));
995 die (EX_USAGE, _("mount: only root can mount %s on %s"), spec, node);
997 if (*flags & MS_USER)
998 *user = getusername();
1001 *flags &= ~(MS_OWNER | MS_GROUP);
1004 /* Check, if there already exists a mounted loop device on the mountpoint node
1005 * with the same parameters.
1008 is_mounted_same_loopfile(const char *node0, const char *loopfile, unsigned long long offset)
1010 struct mntentchn *mnt = NULL;
1014 node = canonicalize(node0);
1016 /* Search for mountpoint node in mtab,
1017 * procceed if any of these has the loop option set or
1018 * the device is a loop device
1020 mnt = getmntdirbackward(node, mnt);
1025 for(; mnt && res == 0; mnt = getmntdirbackward(node, mnt)) {
1028 if (strncmp(mnt->m.mnt_fsname, "/dev/loop", 9) == 0)
1029 res = loopfile_used_with((char *) mnt->m.mnt_fsname,
1032 else if ((p = strstr(mnt->m.mnt_opts, "loop="))) {
1033 char *dev = xstrdup(p+5);
1034 if ((p = strchr(dev, ',')))
1036 res = loopfile_used_with(dev, loopfile, offset);
1046 loop_check(const char **spec, const char **type, int *flags,
1047 int *loop, const char **loopdev, const char **loopfile,
1050 unsigned long long offset, sizelimit;
1053 * In the case of a loop mount, either type is of the form lo@/dev/loop5
1054 * or the option "-o loop=/dev/loop5" or just "-o loop" is given, or
1055 * mount just has to figure things out for itself from the fact that
1056 * spec is not a block device. We do not test for a block device
1057 * immediately: maybe later other types of mountable objects will occur.
1060 *loopdev = opt_loopdev;
1062 looptype = (*type && strncmp("lo@", *type, 3) == 0);
1065 error(_("mount: loop device specified twice"));
1066 *loopdev = *type + 3;
1067 *type = opt_vfstype;
1068 } else if (opt_vfstype) {
1070 error(_("mount: type specified twice"));
1072 *type = opt_vfstype;
1075 *loop = ((*flags & MS_LOOP) || *loopdev || opt_offset || opt_sizelimit || opt_encryption);
1082 printf(_("mount: skipping the setup of a loop device\n"));
1084 int loop_opts = SETLOOP_AUTOCLEAR; /* always attempt autoclear */
1087 if (*flags & MS_RDONLY)
1088 loop_opts |= SETLOOP_RDONLY;
1090 offset = opt_offset ? strtoull(opt_offset, NULL, 0) : 0;
1091 sizelimit = opt_sizelimit ? strtoull(opt_sizelimit, NULL, 0) : 0;
1093 if (is_mounted_same_loopfile(node, *loopfile, offset)) {
1094 error(_("mount: according to mtab %s is already mounted on %s as loop"), *loopfile, node);
1099 if (!*loopdev || !**loopdev)
1100 *loopdev = find_unused_loop_device();
1102 return EX_SYSERR; /* no more loop devices */
1104 printf(_("mount: going to use the loop device %s\n"), *loopdev);
1106 if ((res = set_loop(*loopdev, *loopfile, offset, sizelimit,
1107 opt_encryption, pfd, &loop_opts))) {
1109 /* loop dev has been grabbed by some other process,
1110 try again, if not given explicitly */
1113 printf(_("mount: stolen loop=%s ...trying again\n"), *loopdev);
1118 error(_("mount: stolen loop=%s"), *loopdev);
1123 printf(_("mount: failed setting up loop device\n"));
1131 } while (!*loopdev);
1134 printf(_("mount: setup loop device successfully\n"));
1137 if (loop_opts & SETLOOP_RDONLY)
1138 *flags |= MS_RDONLY;
1140 if (loop_opts & SETLOOP_AUTOCLEAR)
1141 /* Prevent recording loop dev in mtab for cleanup on umount */
1150 update_mtab_entry(const char *spec, const char *node, const char *type,
1151 const char *opts, int flags, int freq, int pass) {
1152 struct my_mntent mnt;
1154 mnt.mnt_fsname = is_pseudo_fs(type) ? xstrdup(spec) : canonicalize(spec);
1155 mnt.mnt_dir = canonicalize (node);
1156 mnt.mnt_type = type;
1157 mnt.mnt_opts = opts;
1158 mnt.mnt_freq = freq;
1159 mnt.mnt_passno = pass;
1161 /* We get chatty now rather than after the update to mtab since the
1162 mount succeeded, even if the write to /etc/mtab should fail. */
1166 if (!nomtab && mtab_does_not_exist()) {
1168 printf(_("mount: no %s found - creating it..\n"),
1173 if (!nomtab && mtab_is_writable()) {
1174 if (flags & MS_REMOUNT)
1175 update_mtab (mnt.mnt_dir, &mnt);
1176 else if (flags & MS_MOVE)
1177 update_mtab(mnt.mnt_fsname, &mnt);
1182 mfp = my_setmntent(_PATH_MOUNTED, "a+");
1183 if (mfp == NULL || mfp->mntent_fp == NULL) {
1185 error(_("mount: can't open %s: %s"), _PATH_MOUNTED,
1188 if ((my_addmntent (mfp, &mnt)) == 1) {
1190 error(_("mount: error writing %s: %s"),
1191 _PATH_MOUNTED, strerror (errsv));
1198 my_free(mnt.mnt_fsname);
1199 my_free(mnt.mnt_dir);
1206 _("mount: argument to -p or --pass-fd must be a number"));
1211 cdrom_setspeed(const char *spec) {
1212 #define CDROM_SELECT_SPEED 0x5322 /* Set the CD-ROM speed */
1215 int speed = atoi(opt_speed);
1217 if ((cdrom = open(spec, O_RDONLY | O_NONBLOCK)) < 0)
1219 _("mount: cannot open %s for setting speed"),
1221 if (ioctl(cdrom, CDROM_SELECT_SPEED, speed) < 0)
1222 die(EX_FAIL, _("mount: cannot set speed: %s"),
1230 * Try to mount one file system.
1232 * returns: 0: OK, EX_SYSERR, EX_FAIL, return code from nfsmount,
1233 * return status from wait
1236 try_mount_one (const char *spec0, const char *node0, const char *types0,
1237 const char *opts0, int freq, int pass, int ro) {
1238 int res = 0, status = 0, special = 0;
1239 int mnt5_res = 0; /* only for gcc */
1242 char *extra_opts; /* written in mtab */
1243 char *mount_opts; /* actually used on system call */
1244 const char *opts, *spec, *node, *types;
1247 const char *loopdev = 0, *loopfile = 0;
1248 struct stat statbuf;
1249 int retries = 0; /* Nr of retries for mount in case of ENOMEDIUM */
1251 /* copies for freeing on exit */
1252 const char *opts1, *spec1, *node1, *types1, *extra_opts1;
1255 printf("mount: spec: \"%s\"\n", spec0);
1256 printf("mount: node: \"%s\"\n", node0);
1257 printf("mount: types: \"%s\"\n", types0);
1258 printf("mount: opts: \"%s\"\n", opts0);
1261 spec = spec1 = xstrdup(spec0);
1262 node = node1 = xstrdup(node0);
1263 types = types1 = xstrdup(types0);
1264 opts = opts1 = xstrdup(opts0);
1266 parse_opts (opts, &flags, &extra_opts);
1267 extra_opts1 = extra_opts;
1269 /* quietly succeed for fstab entries that don't get mounted automatically */
1270 if (mount_all && (flags & MS_NOAUTO))
1273 restricted_check(spec, node, &flags, &user);
1275 /* The "mount -f" checks for for existing record in /etc/mtab (with
1276 * regular non-fake mount this is usually done by kernel)
1278 if (!(flags & MS_REMOUNT) && fake && mounted (spec, node))
1279 die(EX_USAGE, _("mount: according to mtab, "
1280 "%s is already mounted on %s\n"),
1283 mount_opts = extra_opts;
1286 cdrom_setspeed(spec);
1288 if (!(flags & MS_REMOUNT)) {
1290 * Don't set up a (new) loop device if we only remount - this left
1291 * stale assignments of files to loop devices. Nasty when used for
1294 res = loop_check(&spec, &types, &flags, &loop, &loopdev, &loopfile, node);
1300 opt_loopdev = loopdev;
1302 if (flags & (MS_BIND | MS_MOVE | MS_PROPAGATION))
1306 * Call mount.TYPE for types that require a separate mount program.
1307 * For the moment these types are ncpfs and smbfs. Maybe also vxfs.
1308 * All such special things must occur isolated in the types string.
1310 if (check_special_mountprog(spec, node, types, flags, extra_opts, &status)) {
1316 block_signals (SIG_BLOCK);
1319 mnt5_res = guess_fstype_and_mount (spec, node, &types, flags & ~MS_NOSYS,
1320 mount_opts, &special, &status);
1323 block_signals (SIG_UNBLOCK);
1329 if (fake || mnt5_res == 0) {
1330 /* Mount succeeded, report this (if verbose) and write mtab entry. */
1332 if (!(mounttype & MS_PROPAGATION)) {
1333 update_mtab_entry(loop ? loopfile : spec,
1335 types ? types : "unknown",
1336 fix_opts_string (flags & ~MS_NOMTAB, extra_opts, user),
1342 block_signals (SIG_UNBLOCK);
1352 block_signals (SIG_UNBLOCK);
1354 /* Mount failed, complain, but don't die. */
1358 error (_("mount: I could not determine the filesystem type, "
1359 "and none was specified"));
1361 error (_("mount: you must specify the filesystem type"));
1362 } else if (mnt5_res != -1) {
1363 /* should not happen */
1364 error (_("mount: mount failed"));
1368 if (geteuid() == 0) {
1369 if (stat (node, &statbuf) || !S_ISDIR(statbuf.st_mode))
1370 error (_("mount: mount point %s is not a directory"), node);
1372 error (_("mount: permission denied"));
1374 error (_("mount: must be superuser to use mount"));
1377 if (flags & MS_REMOUNT) {
1378 error (_("mount: %s is busy"), node);
1379 } else if (!strcmp(types, "proc") && !strcmp(node, "/proc")) {
1380 /* heuristic: if /proc/version exists, then probably proc is mounted */
1381 if (stat ("/proc/version", &statbuf)) /* proc mounted? */
1382 error (_("mount: %s is busy"), node); /* no */
1383 else if (!mount_all || verbose) /* yes, don't mention it */
1384 error (_("mount: proc already mounted"));
1386 error (_("mount: %s already mounted or %s busy"), spec, node);
1387 already (spec, node);
1391 if (lstat (node, &statbuf))
1392 error (_("mount: mount point %s does not exist"), node);
1393 else if (stat (node, &statbuf))
1394 error (_("mount: mount point %s is a symbolic link to nowhere"),
1396 else if (stat (spec, &statbuf)) {
1399 error (_("mount: special device %s does not exist"), spec);
1406 if (stat (node, &statbuf) || ! S_ISDIR(statbuf.st_mode))
1407 error (_("mount: mount point %s is not a directory"), node);
1408 else if (stat (spec, &statbuf) && errno == ENOTDIR) {
1411 error (_("mount: special device %s does not exist\n"
1412 " (a path prefix is not a directory)\n"), spec);
1420 unsigned long long size = 0;
1422 if (flags & MS_REMOUNT) {
1423 error (_("mount: %s not mounted already, or bad option"), node);
1425 error (_("mount: wrong fs type, bad option, bad superblock on %s,\n"
1426 " missing codepage or helper program, or other error"),
1429 if (stat(spec, &statbuf) < 0) {
1430 if (errno == ENOENT) /* network FS? */
1432 " (for several filesystems (e.g. nfs, cifs) you might\n"
1433 " need a /sbin/mount.<type> helper program)"));
1435 } else if (S_ISBLK(statbuf.st_mode)
1436 && (fd = open(spec, O_RDONLY | O_NONBLOCK)) >= 0) {
1438 if (blkdev_get_size(fd, &size) == 0) {
1439 if (size == 0 && !loop)
1441 " (could this be the IDE device where you in fact use\n"
1442 " ide-scsi so that sr0 or sda or so is needed?)"));
1444 if (size && size <= 2)
1446 " (aren't you trying to mount an extended partition,\n"
1447 " instead of some logical partition inside?)"));
1453 " In some cases useful info is found in syslog - try\n"
1454 " dmesg | tail or so\n"));
1459 error (_("mount table full")); break;
1461 error (_("mount: %s: can't read superblock"), spec); break;
1464 int pfs = known_fstype_in_procfs(types);
1466 if (pfs == 1 || !strcmp(types, "guess"))
1467 error(_("mount: %s: unknown device"), spec);
1468 else if (pfs == 0) {
1472 error (_("mount: unknown filesystem type '%s'"), types);
1474 /* maybe this loser asked for FAT or ISO9660 or isofs */
1475 lowtype = xstrdup(types);
1477 for(p=lowtype; *p; p++) {
1478 if(tolower(*p) != *p) {
1483 if (u && known_fstype_in_procfs(lowtype) == 1)
1484 error (_("mount: probably you meant %s"), lowtype);
1485 else if (!strncmp(lowtype, "iso", 3) &&
1486 known_fstype_in_procfs("iso9660") == 1)
1487 error (_("mount: maybe you meant 'iso9660'?"));
1488 else if (!strncmp(lowtype, "fat", 3) &&
1489 known_fstype_in_procfs("vfat") == 1)
1490 error (_("mount: maybe you meant 'vfat'?"));
1493 error (_("mount: %s has wrong device number or fs type %s not supported"),
1500 if (stat (spec, &statbuf)) /* strange ... */
1501 error (_("mount: %s is not a block device, and stat fails?"), spec);
1502 else if (S_ISBLK(statbuf.st_mode))
1503 error (_("mount: the kernel does not recognize %s as a block device\n"
1504 " (maybe `insmod driver'?)"), spec);
1505 else if (S_ISREG(statbuf.st_mode))
1506 error (_("mount: %s is not a block device (maybe try `-o loop'?)"),
1509 error (_("mount: %s is not a block device"), spec);
1514 error (_("mount: %s is not a valid block device"), spec); break;
1515 case EACCES: /* pre-linux 1.1.38, 1.1.41 and later */
1516 case EROFS: /* linux 1.1.38 and later */
1517 { char *bd = (loop ? "" : _("block device "));
1518 if (ro || (flags & MS_RDONLY)) {
1519 error (_("mount: cannot mount %s%s read-only"),
1522 } else if (readwrite) {
1523 error (_("mount: %s%s is write-protected but explicit `-w' flag given"),
1526 } else if (flags & MS_REMOUNT) {
1527 error (_("mount: cannot remount %s%s read-write, is write-protected"),
1535 char *opts2 = append_opt(xstrdup(opts), "ro", NULL);
1537 opts = opts1 = opts2;
1540 if (types && !strcmp(types, "guess"))
1542 error (_("mount: %s%s is write-protected, mounting read-only"),
1544 res = try_mount_one (spec0, node0, types, opts, freq, pass, 1);
1550 if (retries < CRDOM_NOMEDIUM_RETRIES) {
1552 printf(_("mount: no medium found on %s ...trying again\n"),
1558 error(_("mount: no medium found on %s"), spec);
1561 error ("mount: %s", strerror (mnt_err)); break;
1568 #if defined(HAVE_LIBSELINUX) && defined(HAVE_SECURITY_GET_INITIAL_CONTEXT)
1569 if (res != EX_FAIL && verbose && is_selinux_enabled() > 0) {
1570 security_context_t raw = NULL, def = NULL;
1572 if (getfilecon(node, &raw) > 0 &&
1573 security_get_initial_context("file", &def) == 0) {
1575 if (!selinux_file_context_cmp(raw, def))
1576 printf(_("mount: %s does not contain SELinux labels.\n"
1577 " You just mounted an file system that supports labels which does not\n"
1578 " contain labels, onto an SELinux box. It is likely that confined\n"
1579 " applications will generate AVC messages and not be allowed access to\n"
1580 " this file system. For more details see restorecon(8) and mount(8).\n"),
1588 my_free(extra_opts1);
1598 subst_string(const char *s, const char *sub, int sublen, const char *repl) {
1601 n = (char *) xmalloc(strlen(s)-sublen+strlen(repl)+1);
1602 strncpy (n, s, sub-s);
1603 strcpy (n + (sub-s), repl);
1604 strcat (n, sub+sublen);
1609 usersubst(const char *opts) {
1617 if (opts && (w = strstr(opts, s)) != NULL) {
1618 sprintf(id, "uid=%d", getuid());
1619 opts = subst_string(opts, w, strlen(s), id);
1622 if (opts && (w = strstr(opts, s)) != NULL) {
1623 sprintf(id, "gid=%d", getgid());
1624 opts = subst_string(opts, w, strlen(s), id);
1626 return xstrdup(opts);
1630 is_existing_file (const char *s) {
1631 struct stat statbuf;
1633 return (stat(s, &statbuf) == 0);
1637 * Return 0 for success (either mounted sth or -a and NOAUTO was given)
1640 mount_one (const char *spec, const char *node, const char *types,
1641 const char *fstabopts, char *cmdlineopts, int freq, int pass) {
1645 /* Substitute values in opts, if required */
1646 opts = usersubst(fstabopts);
1648 /* Merge the fstab and command line options. */
1649 opts = append_opt(opts, cmdlineopts, NULL);
1651 if (types == NULL && !mounttype && !is_existing_file(spec)) {
1652 if (strchr (spec, ':') != NULL) {
1655 printf(_("mount: no type was given - "
1656 "I'll assume nfs because of "
1658 } else if(!strncmp(spec, "//", 2)) {
1661 printf(_("mount: no type was given - "
1662 "I'll assume cifs because of "
1663 "the // prefix\n"));
1667 /* Handle possible LABEL= and UUID= forms of spec */
1668 if (types == NULL || (strncmp(types, "nfs", 3) &&
1669 strncmp(types, "cifs", 4) &&
1670 strncmp(types, "smbfs", 5))) {
1671 nspec = spec_to_devname(spec);
1676 return try_mount_one (spec, node, types, opts, freq, pass, 0);
1679 /* Check if an fsname/dir pair was already in the old mtab. */
1681 mounted (const char *spec0, const char *node0) {
1682 struct mntentchn *mc, *mc0;
1683 const char *spec, *node;
1686 /* Handle possible UUID= and LABEL= in spec */
1687 spec = spec_to_devname(spec0);
1691 node = canonicalize(node0);
1694 for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt)
1695 if (streq (spec, mc->m.mnt_fsname) &&
1696 streq (node, mc->m.mnt_dir)) {
1707 /* avoid using stat() on things we are not going to mount anyway.. */
1709 has_noauto (const char *opts) {
1714 s = strstr(opts, "noauto");
1717 return (s == opts || s[-1] == ',') && (s[6] == 0 || s[6] == ',');
1720 /* Mount all filesystems of the specified types except swap and root. */
1721 /* With the --fork option: fork and let different incarnations of
1722 mount handle different filesystems. However, try to avoid several
1723 simultaneous mounts on the same physical disk, since that is very slow. */
1724 #define DISKMAJOR(m) (((int) m) & ~0xf)
1727 do_mount_all (char *types, char *options, char *test_opts) {
1728 struct mntentchn *mc, *mc0, *mtmp;
1730 struct stat statbuf;
1734 struct mntentchn *mec;
1735 struct mntentchn *meclast;
1737 } childhead, *childtail, *cp;
1741 /* build a chain of what we have to do, or maybe
1742 several chains, one for each major or NFS host */
1744 childtail = &childhead;
1746 for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt) {
1747 if (has_noauto (mc->m.mnt_opts))
1749 if (matching_type (mc->m.mnt_type, types)
1750 && matching_opts (mc->m.mnt_opts, test_opts)
1751 && !streq (mc->m.mnt_dir, "/")
1752 && !streq (mc->m.mnt_dir, "root")) {
1754 if (mounted (mc->m.mnt_fsname, mc->m.mnt_dir)) {
1756 printf(_("mount: %s already mounted "
1763 mtmp = (struct mntentchn *) xmalloc(sizeof(*mtmp));
1768 if (stat(mc->m.mnt_fsname, &statbuf) == 0 &&
1769 S_ISBLK(statbuf.st_mode)) {
1770 sprintf(major, "#%x",
1771 DISKMAJOR(statbuf.st_rdev));
1774 if (strcmp(mc->m.mnt_type, "nfs") == 0) {
1775 g = xstrdup(mc->m.mnt_fsname);
1776 colon = strchr(g, ':');
1782 for (cp = childhead.nxt; cp; cp = cp->nxt)
1784 strcmp(cp->group, g) == 0) {
1785 cp->meclast->nxt = mtmp;
1790 cp = (struct child *) xmalloc(sizeof *cp);
1792 cp->mec = cp->meclast = mtmp;
1793 cp->group = xstrdup(g);
1795 childtail->nxt = cp;
1802 /* now do everything */
1803 for (cp = childhead.nxt; cp; cp = cp->nxt) {
1809 error(_("mount: cannot fork: %s"),
1816 /* if child, or not forked, do the mounting */
1817 if (p == 0 || p == -1) {
1818 for (mc = cp->mec; mc; mc = mc->nxt) {
1819 status |= mount_one (mc->m.mnt_fsname,
1826 status |= EX_SOMEOK;
1832 /* wait for children, if any */
1833 while ((cp = childhead.nxt) != NULL) {
1834 childhead.nxt = cp->nxt;
1838 if(waitpid(cp->pid, &ret, 0) == -1) {
1842 } else if (WIFEXITED(ret))
1843 status |= WEXITSTATUS(ret);
1845 status |= EX_SYSERR;
1849 status |= EX_SOMEOK;
1853 static struct option longopts[] = {
1854 { "all", 0, 0, 'a' },
1855 { "fake", 0, 0, 'f' },
1856 { "fork", 0, 0, 'F' },
1857 { "help", 0, 0, 'h' },
1858 { "no-mtab", 0, 0, 'n' },
1859 { "read-only", 0, 0, 'r' },
1860 { "ro", 0, 0, 'r' },
1861 { "verbose", 0, 0, 'v' },
1862 { "version", 0, 0, 'V' },
1863 { "read-write", 0, 0, 'w' },
1864 { "rw", 0, 0, 'w' },
1865 { "options", 1, 0, 'o' },
1866 { "test-opts", 1, 0, 'O' },
1867 { "pass-fd", 1, 0, 'p' },
1868 { "types", 1, 0, 't' },
1869 { "bind", 0, 0, 'B' },
1870 { "move", 0, 0, 'M' },
1871 { "guess-fstype", 1, 0, 134 },
1872 { "rbind", 0, 0, 'R' },
1873 { "make-shared", 0, 0, 136 },
1874 { "make-slave", 0, 0, 137 },
1875 { "make-private", 0, 0, 138 },
1876 { "make-unbindable", 0, 0, 139 },
1877 { "make-rshared", 0, 0, 140 },
1878 { "make-rslave", 0, 0, 141 },
1879 { "make-rprivate", 0, 0, 142 },
1880 { "make-runbindable", 0, 0, 143 },
1881 { "internal-only", 0, 0, 'i' },
1885 /* Keep the usage message at max 22 lines, each at most 70 chars long.
1886 The user should not need a pager to read it. */
1888 usage (FILE *fp, int n) {
1890 "Usage: mount -V : print version\n"
1891 " mount -h : print this help\n"
1892 " mount : list mounted filesystems\n"
1893 " mount -l : idem, including volume labels\n"
1894 "So far the informational part. Next the mounting.\n"
1895 "The command is `mount [-t fstype] something somewhere'.\n"
1896 "Details found in /etc/fstab may be omitted.\n"
1897 " mount -a [-t|-O] ... : mount all stuff from /etc/fstab\n"
1898 " mount device : mount device at the known place\n"
1899 " mount directory : mount known device here\n"
1900 " mount -t type dev dir : ordinary mount command\n"
1901 "Note that one does not really mount a device, one mounts\n"
1902 "a filesystem (of the given type) found on the device.\n"
1903 "One can also mount an already visible directory tree elsewhere:\n"
1904 " mount --bind olddir newdir\n"
1905 "or move a subtree:\n"
1906 " mount --move olddir newdir\n"
1907 "One can change the type of mount containing the directory dir:\n"
1908 " mount --make-shared dir\n"
1909 " mount --make-slave dir\n"
1910 " mount --make-private dir\n"
1911 " mount --make-unbindable dir\n"
1912 "One can change the type of all the mounts in a mount subtree\n"
1913 "containing the directory dir:\n"
1914 " mount --make-rshared dir\n"
1915 " mount --make-rslave dir\n"
1916 " mount --make-rprivate dir\n"
1917 " mount --make-runbindable dir\n"
1918 "A device can be given by name, say /dev/hda1 or /dev/cdrom,\n"
1919 "or by label, using -L label or by uuid, using -U uuid .\n"
1920 "Other options: [-nfFrsvw] [-o options] [-p passwdfd].\n"
1921 "For many more details, say man 8 mount .\n"
1928 /* returns mount entry from fstab */
1929 static struct mntentchn *
1930 getfs(const char *spec, const char *uuid, const char *label)
1932 struct mntentchn *mc = NULL;
1933 const char *devname = NULL;
1935 if (!spec && !uuid && !label)
1939 * A) 99% of all cases, the spec on cmdline matches
1940 * with spec in fstab
1943 mc = getfs_by_uuid(uuid);
1945 mc = getfs_by_label(label);
1947 mc = getfs_by_spec(spec);
1950 mc = getfs_by_dir(spec);
1956 * B) UUID or LABEL on cmdline, but devname in fstab
1959 devname = fsprobe_get_devname_by_uuid(uuid);
1961 devname = fsprobe_get_devname_by_label(label);
1963 devname = spec_to_devname(spec);
1966 mc = getfs_by_devname(devname);
1971 if (!mc && devname) {
1972 const char *id = NULL;
1974 if (!label && (!spec || strncmp(spec, "LABEL=", 6))) {
1975 id = fsprobe_get_label_by_devname(devname);
1977 mc = getfs_by_label(id);
1979 if (!mc && !uuid && (!spec || strncmp(spec, "UUID=", 5))) {
1980 id = fsprobe_get_uuid_by_devname(devname);
1982 mc = getfs_by_uuid(id);
1987 /* use real device name to avoid repetitional
1988 * conversion from LABEL/UUID to devname
1990 my_free(mc->m.mnt_fsname);
1991 mc->m.mnt_fsname = xstrdup(devname);
1996 * D) remount -- try /etc/mtab
1997 * Earlier mtab was tried first, but this would sometimes try the
1998 * wrong mount in case mtab had the root device entry wrong.
2000 if (!mc && (devname || spec))
2001 mc = getmntfile (devname ? devname : spec);
2009 print_version(int rc) {
2010 printf( "mount from %s (with "
2011 #ifdef HAVE_LIBBLKID
2016 #ifdef HAVE_LIBSELINUX
2019 " support)\n", PACKAGE_STRING);
2024 main(int argc, char *argv[]) {
2025 int c, result = 0, specseen;
2026 char *options = NULL, *test_opts = NULL, *node;
2027 const char *spec = NULL;
2032 struct mntentchn *mc;
2036 setlocale(LC_ALL, "");
2037 bindtextdomain(PACKAGE, LOCALEDIR);
2038 textdomain(PACKAGE);
2041 if ((p = strrchr(progname, '/')) != NULL)
2046 /* People report that a mount called from init without console
2047 writes error messages to /etc/mtab
2048 Let us try to avoid getting fd's 0,1,2 */
2049 while((fd = open("/dev/null", O_RDWR)) == 0 || fd == 1 || fd == 2) ;
2055 #ifdef DO_PS_FIDDLING
2056 initproctitle(argc, argv);
2059 while ((c = getopt_long (argc, argv, "aBfFhilL:Mno:O:p:rRsU:vVwt:",
2060 longopts, NULL)) != -1) {
2062 case 'a': /* mount everything in fstab */
2065 case 'B': /* bind */
2066 mounttype = MS_BIND;
2068 case 'f': /* fake: don't actually call mount(2) */
2074 case 'h': /* help */
2078 external_allowed = 0;
2081 list_with_volumelabel = 1;
2086 case 'M': /* move */
2087 mounttype = MS_MOVE;
2089 case 'n': /* do not write /etc/mtab */
2092 case 'o': /* specify mount options */
2093 options = append_opt(options, optarg, NULL);
2095 case 'O': /* with -t: mount only if (not) opt */
2096 test_opts = append_opt(test_opts, optarg, NULL);
2098 case 'p': /* fd on which to read passwd */
2101 case 'r': /* mount readonly */
2105 case 'R': /* rbind */
2106 mounttype = (MS_BIND | MS_REC);
2108 case 's': /* allow sloppy mount options */
2111 case 't': /* specify file system types */
2117 case 'v': /* be chatty - more so if repeated */
2120 case 'V': /* version */
2121 print_version(EXIT_SUCCESS);
2123 case 'w': /* mount read/write */
2131 /* undocumented, may go away again:
2132 call: mount --guess-fstype device
2133 use only for testing purposes -
2134 the guessing is not reliable at all */
2137 fstype = fsprobe_get_fstype_by_devname(optarg);
2138 printf("%s\n", fstype ? fstype : "unknown");
2139 exit(fstype ? 0 : EX_FAIL);
2143 mounttype = MS_SHARED;
2147 mounttype = MS_SLAVE;
2151 mounttype = MS_PRIVATE;
2155 mounttype = MS_UNBINDABLE;
2159 mounttype = (MS_SHARED | MS_REC);
2163 mounttype = (MS_SLAVE | MS_REC);
2167 mounttype = (MS_PRIVATE | MS_REC);
2171 mounttype = (MS_UNBINDABLE | MS_REC);
2176 usage (stderr, EX_USAGE);
2181 printf("mount: fstab path: \"%s\"\n", _PATH_MNTTAB);
2182 printf("mount: mtab path: \"%s\"\n", _PATH_MOUNTED);
2183 printf("mount: lock path: \"%s\"\n", _PATH_MOUNTED_LOCK);
2184 printf("mount: temp path: \"%s\"\n", _PATH_MOUNTED_TMP);
2185 printf("mount: UID: %d\n", getuid());
2186 printf("mount: eUID: %d\n", geteuid());
2192 specseen = (uuid || label) ? 1 : 0; /* yes, .. i know */
2194 if (argc+specseen == 0 && !mount_all) {
2195 if (options || mounttype)
2196 usage (stderr, EX_USAGE);
2197 return print_all (types);
2201 const uid_t ruid = getuid();
2202 const uid_t euid = geteuid();
2204 /* if we're really root and aren't running setuid */
2205 if (((uid_t)0 == ruid) && (ruid == euid)) {
2211 (types || options || readwrite || nomtab || mount_all ||
2212 fake || mounttype || (argc + specseen) != 1)) {
2213 die (EX_USAGE, _("mount: only root can do that"));
2216 atexit(unlock_mtab);
2218 switch (argc+specseen) {
2221 result = do_mount_all (types, options, test_opts);
2222 if (result == 0 && verbose && !fake)
2223 error(_("nothing was mounted"));
2227 /* mount [-nfrvw] [-o options] special | node
2228 * mount -L label (or -U uuid)
2229 * (/etc/fstab is necessary)
2232 usage (stderr, EX_USAGE);
2235 mc = getfs(NULL, uuid, label);
2237 mc = getfs(*argv, NULL, NULL);
2241 die (EX_USAGE, _("mount: no such partition found"));
2244 _("mount: can't find %s in %s or %s"),
2245 *argv, _PATH_MNTTAB, _PATH_MOUNTED);
2248 result = mount_one (xstrdup (mc->m.mnt_fsname),
2249 xstrdup (mc->m.mnt_dir),
2250 xstrdup (mc->m.mnt_type),
2251 mc->m.mnt_opts, options, 0, 0);
2255 /* mount special node (/etc/fstab is not necessary) */
2257 /* mount -L label node (or -U uuid) */
2258 spec = uuid ? fsprobe_get_devname_by_uuid(uuid) :
2259 fsprobe_get_devname_by_label(label);
2262 /* mount special node */
2267 die (EX_USAGE, _("mount: no such partition found"));
2269 result = mount_one (spec, node, types, NULL, options, 0, 0);
2273 usage (stderr, EX_USAGE);
2276 if (result == EX_SOMEOK)