]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - mount-deprecated/mount.c
e3e1bfe4660f200a51ef950c86b266845291fc2d
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"
35 #include "mount_mntent.h"
38 #include "linux_version.h"
39 #include "getusername.h"
44 #include "closestream.h"
47 #define DO_PS_FIDDLING
50 #include "setproctitle.h"
53 /* True for fake mount (-f). */
56 /* True if we are allowed to call /sbin/mount.${FSTYPE} */
57 static int external_allowed
= 1;
59 /* Don't write an entry in /etc/mtab (-n). */
60 static int nomtab
= 0;
62 /* True for explicit readonly (-r). */
63 static int readonly
= 0;
65 /* Nonzero for sloppy (-s). */
66 static int sloppy
= 0;
68 /* True for explicit read/write (-w). */
69 static int readwrite
= 0;
71 /* True for all mount (-a). */
72 static int mount_all
= 0;
74 /* True for fork() during all mount (-F). */
75 static int optfork
= 0;
77 /* Add volumelabel in a listing of mounted devices (-l). */
78 static int list_with_volumelabel
= 0;
80 /* Nonzero for mount {bind|move|make-shared|make-private|
81 * make-unbindable|make-slave}
83 static int mounttype
= 0;
85 /* True if (ruid != euid) or (0 != ruid), i.e. only "user" mounts permitted. */
86 static int restricted
= 1;
88 /* Contains the fd to read the passphrase from, if any. */
91 /* mount(2) options */
100 /* Map from -o and fstab option strings to the flag argument to mount(2). */
102 const char *opt
; /* option name */
103 int skip
; /* skip in mtab option string */
104 int inv
; /* true if flag value should be inverted */
105 int mask
; /* flag mask value */
106 int cmask
; /* comments mask */
109 /* Custom mount options for our own purposes. */
110 /* Maybe these should now be freed for kernel use again */
111 #define MS_NOAUTO 0x80000000
112 #define MS_USERS 0x40000000
113 #define MS_USER 0x20000000
114 #define MS_OWNER 0x10000000
115 #define MS_GROUP 0x08000000
116 #define MS_COMMENT 0x02000000
117 #define MS_LOOP 0x00010000
119 #define MS_COMMENT_NOFAIL (1 << 1)
120 #define MS_COMMENT_NETDEV (1 << 2)
122 /* Options that we keep the mount system call from seeing. */
123 #define MS_NOSYS (MS_NOAUTO|MS_USERS|MS_USER|MS_COMMENT|MS_LOOP)
125 /* Options that we keep from appearing in the options field in the mtab. */
126 #define MS_NOMTAB (MS_REMOUNT|MS_NOAUTO|MS_USERS|MS_USER)
128 #define MS_PROPAGATION (MS_SHARED|MS_SLAVE|MS_UNBINDABLE|MS_PRIVATE)
130 /* Options that we make ordinary users have by default. */
131 #define MS_SECURE (MS_NOEXEC|MS_NOSUID|MS_NODEV)
133 /* Options that we make owner-mounted devices have by default */
134 #define MS_OWNERSECURE (MS_NOSUID|MS_NODEV)
136 static const struct opt_map opt_map
[] = {
137 { "defaults", 0, 0, 0 }, /* default options */
138 { "ro", 1, 0, MS_RDONLY
}, /* read-only */
139 { "rw", 1, 1, MS_RDONLY
}, /* read-write */
140 { "exec", 0, 1, MS_NOEXEC
}, /* permit execution of binaries */
141 { "noexec", 0, 0, MS_NOEXEC
}, /* don't execute binaries */
142 { "suid", 0, 1, MS_NOSUID
}, /* honor suid executables */
143 { "nosuid", 0, 0, MS_NOSUID
}, /* don't honor suid executables */
144 { "dev", 0, 1, MS_NODEV
}, /* interpret device files */
145 { "nodev", 0, 0, MS_NODEV
}, /* don't interpret devices */
146 { "sync", 0, 0, MS_SYNCHRONOUS
}, /* synchronous I/O */
147 { "async", 0, 1, MS_SYNCHRONOUS
}, /* asynchronous I/O */
148 { "dirsync", 0, 0, MS_DIRSYNC
}, /* synchronous directory modifications */
149 { "remount", 0, 0, MS_REMOUNT
}, /* Alter flags of mounted FS */
150 { "bind", 0, 0, MS_BIND
}, /* Remount part of tree elsewhere */
151 { "rbind", 0, 0, MS_BIND
|MS_REC
}, /* Idem, plus mounted subtrees */
152 { "auto", 0, 1, MS_NOAUTO
}, /* Can be mounted using -a */
153 { "noauto", 0, 0, MS_NOAUTO
}, /* Can only be mounted explicitly */
154 { "users", 0, 0, MS_USERS
}, /* Allow ordinary user to mount */
155 { "nousers", 0, 1, MS_USERS
}, /* Forbid ordinary user to mount */
156 { "user", 0, 0, MS_USER
}, /* Allow ordinary user to mount */
157 { "nouser", 0, 1, MS_USER
}, /* Forbid ordinary user to mount */
158 { "owner", 0, 0, MS_OWNER
}, /* Let the owner of the device mount */
159 { "noowner", 0, 1, MS_OWNER
}, /* Device owner has no special privs */
160 { "group", 0, 0, MS_GROUP
}, /* Let the group of the device mount */
161 { "nogroup", 0, 1, MS_GROUP
}, /* Device group has no special privs */
162 { "_netdev", 0, 0, MS_COMMENT
, MS_COMMENT_NETDEV
}, /* Device requires network */
163 { "comment", 0, 0, MS_COMMENT
}, /* fstab comment only (kudzu,_netdev)*/
165 /* add new options here */
167 { "sub", 0, 1, MS_NOSUB
}, /* allow submounts */
168 { "nosub", 0, 0, MS_NOSUB
}, /* don't allow submounts */
171 { "silent", 0, 0, MS_SILENT
}, /* be quiet */
172 { "loud", 0, 1, MS_SILENT
}, /* print out messages. */
175 { "mand", 0, 0, MS_MANDLOCK
}, /* Allow mandatory locks on this FS */
176 { "nomand", 0, 1, MS_MANDLOCK
}, /* Forbid mandatory locks on this FS */
178 { "loop", 1, 0, MS_LOOP
}, /* use a loop device */
180 { "atime", 0, 1, MS_NOATIME
}, /* Update access time */
181 { "noatime", 0, 0, MS_NOATIME
}, /* Do not update access time */
184 { "iversion", 0, 0, MS_I_VERSION
}, /* Update inode I_version time */
185 { "noiversion", 0, 1, MS_I_VERSION
}, /* Don't update inode I_version time */
188 { "diratime", 0, 1, MS_NODIRATIME
}, /* Update dir access times */
189 { "nodiratime", 0, 0, MS_NODIRATIME
},/* Do not update dir access times */
192 { "relatime", 0, 0, MS_RELATIME
}, /* Update access times relative to
194 { "norelatime", 0, 1, MS_RELATIME
}, /* Update access time without regard
197 #ifdef MS_STRICTATIME
198 { "strictatime", 0, 0, MS_STRICTATIME
}, /* Strict atime semantics */
199 { "nostrictatime", 0, 1, MS_STRICTATIME
}, /* kernel default atime */
201 { "nofail", 0, 0, MS_COMMENT
, MS_COMMENT_NOFAIL
}, /* Do not fail if ENOENT on dev */
205 static int opt_nofail
;
206 static int invuser_flags
;
207 static int comment_flags
;
209 static const char *opt_loopdev
, *opt_vfstype
, *opt_offset
, *opt_sizelimit
,
210 *opt_encryption
, *opt_speed
, *opt_comment
, *opt_uhelper
, *opt_helper
;
212 static int is_readonly(const char *node
);
213 static int mounted (const char *spec0
, const char *node0
, struct mntentchn
*fstab_mc
);
214 static int check_special_mountprog(const char *spec
, const char *node
,
215 const char *type
, int flags
, char *extra_opts
, int *status
);
217 static struct string_opt_map
{
221 } string_opt_map
[] = {
222 { "loop=", 0, &opt_loopdev
},
223 { "vfs=", 1, &opt_vfstype
},
224 { "offset=", 0, &opt_offset
},
225 { "sizelimit=", 0, &opt_sizelimit
},
226 { "encryption=", 0, &opt_encryption
},
227 { "speed=", 0, &opt_speed
},
228 { "comment=", 1, &opt_comment
},
229 { "uhelper=", 0, &opt_uhelper
},
230 { "helper=", 0, &opt_helper
},
235 clear_string_opts(void) {
236 struct string_opt_map
*m
;
238 for (m
= &string_opt_map
[0]; m
->tag
; m
++)
243 clear_flags_opts(void) {
250 parse_string_opt(char *s
) {
251 struct string_opt_map
*m
;
254 for (m
= &string_opt_map
[0]; m
->tag
; m
++) {
255 lth
= strlen(m
->tag
);
256 if (!strncmp(s
, m
->tag
, lth
)) {
257 *(m
->valptr
) = xstrdup(s
+ lth
);
264 /* Report on a single mount. */
266 print_one (const struct my_mntent
*me
) {
273 /* users assume backing file name rather than /dev/loopN in
274 * mount(8) output if the device has been initialized by mount(8).
276 if (strncmp(me
->mnt_fsname
, "/dev/loop", 9) == 0 &&
277 loopdev_is_autoclear(me
->mnt_fsname
))
278 fsname
= loopdev_get_backing_file(me
->mnt_fsname
);
281 fsname
= (char *) me
->mnt_fsname
;
283 printf ("%s on %s", fsname
, me
->mnt_dir
);
284 if (me
->mnt_type
!= NULL
&& *(me
->mnt_type
) != '\0')
285 printf (" type %s", me
->mnt_type
);
286 if (me
->mnt_opts
!= NULL
)
287 printf (" (%s)", me
->mnt_opts
);
288 if (list_with_volumelabel
&& is_pseudo_fs(me
->mnt_type
) == 0) {
289 const char *devname
= spec_to_devname(me
->mnt_fsname
);
294 label
= fsprobe_get_label_by_devname(devname
);
298 printf (" [%s]", label
);
306 /* Report on everything in mtab (of the specified types if any). */
308 print_all (char *types
) {
309 struct mntentchn
*mc
, *mc0
;
312 for (mc
= mc0
->nxt
; mc
&& mc
!= mc0
; mc
= mc
->nxt
) {
313 if (matching_type (mc
->m
.mnt_type
, types
))
314 print_one (&(mc
->m
));
317 if (!mtab_does_not_exist() && !mtab_is_a_symlink() && is_readonly(_PATH_MOUNTED
))
319 "mount: warning: /etc/mtab is not writable (e.g. read-only filesystem).\n"
320 " It's possible that information reported by mount(8) is not\n"
321 " up to date. For actual information about system mount points\n"
322 " check the /proc/mounts file.\n\n"));
327 /* reallocates its first arg */
329 append_opt(char *s
, const char *opt
, const char *val
)
335 return xstrdup(opt
); /* opt */
337 return xstrconcat3(NULL
, opt
, val
); /* opt=val */
340 return xstrconcat3(s
, ",", opt
); /* s,opt */
342 return xstrconcat4(s
, ",", opt
, val
); /* s,opt=val */
346 append_numopt(char *s
, const char *opt
, unsigned int num
)
350 snprintf(buf
, sizeof(buf
), "%u", num
);
351 return append_opt(s
, opt
, buf
);
354 #ifdef HAVE_LIBSELINUX
355 /* strip quotes from a "string"
356 * Warning: This function modify the "str" argument.
359 strip_quotes(char *str
)
366 end
= strrchr(str
, '"');
367 if (end
== NULL
|| end
== str
)
368 die (EX_USAGE
, _("mount: improperly quoted option string '%s'"), str
);
374 /* translates SELinux context from human to raw format and
375 * appends it to the mount extra options.
377 * returns -1 on error and 0 on success
380 append_context(const char *optname
, char *optdata
, char **extra_opts
)
382 security_context_t raw
= NULL
;
385 if (is_selinux_enabled() != 1)
386 /* ignore the option if we running without selinux */
389 if (optdata
==NULL
|| *optdata
=='\0' || optname
==NULL
)
392 /* TODO: use strip_quotes() for all mount options? */
393 data
= *optdata
=='"' ? strip_quotes(optdata
) : optdata
;
395 if (selinux_trans_to_raw_context(
396 (security_context_t
) data
, &raw
) == -1 ||
401 printf(_("mount: translated %s '%s' to '%s'\n"),
402 optname
, data
, (char *) raw
);
404 *extra_opts
= append_opt(*extra_opts
, optname
, NULL
);
405 *extra_opts
= xstrconcat4(*extra_opts
, "\"", (char *) raw
, "\"");
411 /* returns newly allocated string without *context= options */
412 static char *remove_context_options(char *opts
)
414 char *begin
= NULL
, *end
= NULL
, *p
;
415 int open_quote
= 0, changed
= 0;
420 opts
= xstrdup(opts
);
422 for (p
= opts
; p
&& *p
; p
++) {
424 begin
= p
; /* begin of the option item */
426 open_quote
^= 1; /* reverse the status */
428 continue; /* still in quoted block */
430 end
= p
; /* terminate the option item */
431 else if (*(p
+ 1) == '\0')
432 end
= p
+ 1; /* end of optstr */
436 if (strncmp(begin
, "context=", 8) == 0 ||
437 strncmp(begin
, "fscontext=", 10) == 0 ||
438 strncmp(begin
, "defcontext=", 11) == 0 ||
439 strncmp(begin
, "rootcontext=", 12) == 0 ||
440 strncmp(begin
, "seclabel", 8) == 0) {
443 if ((begin
== opts
|| *(begin
- 1) == ',') && *end
== ',')
447 memmove(begin
, end
, sz
+ 1);
448 if (!*begin
&& *(begin
- 1) == ',')
457 if (changed
&& verbose
)
458 printf (_("mount: SELinux *context= options are ignore on remount.\n"));
463 static int has_context_option(char *opts
)
465 if (get_option("context=", opts
, NULL
) ||
466 get_option("fscontext=", opts
, NULL
) ||
467 get_option("defcontext=", opts
, NULL
) ||
468 get_option("rootcontext=", opts
, NULL
))
477 * Look for OPT in opt_map table and return mask value.
478 * If OPT isn't found, tack it onto extra_opts (which is non-NULL).
479 * For the options uid= and gid= replace user or group name by its value.
482 parse_opt(char *opt
, int *mask
, int *inv_user
, char **extra_opts
) {
483 const struct opt_map
*om
;
485 for (om
= opt_map
; om
->opt
!= NULL
; om
++)
486 if (streq (opt
, om
->opt
)) {
491 if (om
->inv
&& ((*mask
& MS_USER
) || (*mask
& MS_USERS
))
492 && (om
->mask
& MS_SECURE
))
493 *inv_user
|= om
->mask
;
494 if ((om
->mask
== MS_USER
|| om
->mask
== MS_USERS
)
497 if ((om
->mask
== MS_OWNER
|| om
->mask
== MS_GROUP
)
499 *mask
|= MS_OWNERSECURE
;
501 if (om
->mask
== MS_SILENT
&& om
->inv
) {
506 if (om
->mask
== MS_COMMENT
) {
507 comment_flags
|= om
->cmask
;
508 if (om
->cmask
== MS_COMMENT_NOFAIL
)
514 /* convert nonnumeric ids to numeric */
515 if (!strncmp(opt
, "uid=", 4) && !isdigit(opt
[4])) {
516 struct passwd
*pw
= getpwnam(opt
+4);
519 *extra_opts
= append_numopt(*extra_opts
,
524 if (!strncmp(opt
, "gid=", 4) && !isdigit(opt
[4])) {
525 struct group
*gr
= getgrnam(opt
+4);
528 *extra_opts
= append_numopt(*extra_opts
,
534 #ifdef HAVE_LIBSELINUX
535 if (strncmp(opt
, "context=", 8) == 0 && *(opt
+8)) {
536 if (append_context("context=", opt
+8, extra_opts
) == 0)
539 if (strncmp(opt
, "fscontext=", 10) == 0 && *(opt
+10)) {
540 if (append_context("fscontext=", opt
+10, extra_opts
) == 0)
543 if (strncmp(opt
, "defcontext=", 11) == 0 && *(opt
+11)) {
544 if (append_context("defcontext=", opt
+11, extra_opts
) == 0)
547 if (strncmp(opt
, "rootcontext=", 12) == 0 && *(opt
+12)) {
548 if (append_context("rootcontext=", opt
+12, extra_opts
) == 0)
552 *extra_opts
= append_opt(*extra_opts
, opt
, NULL
);
556 /* Take -o options list and compute 4th and 5th args to mount(2). flags
557 gets the standard options (indicated by bits) and extra_opts all the rest */
559 parse_opts (const char *options
, int *flags
, char **extra_opts
) {
566 if (options
!= NULL
) {
567 char *opts
= xstrdup(options
);
571 for (p
=opts
, opt
=NULL
; p
&& *p
; p
++) {
573 opt
= p
; /* begin of the option item */
575 open_quote
^= 1; /* reverse the status */
577 continue; /* still in quoted block */
579 *p
= '\0'; /* terminate the option item */
580 /* end of option item or last item */
581 if (*p
== '\0' || *(p
+1) == '\0') {
582 if (!parse_string_opt(opt
))
583 parse_opt(opt
, flags
, &invuser_flags
, extra_opts
);
593 *flags
&= ~MS_RDONLY
;
597 /* The propagation flags should not be used together with any
598 * other flags (except MS_REC and MS_SILENT) */
599 if (*flags
& MS_PROPAGATION
)
600 *flags
&= (MS_PROPAGATION
| MS_REC
| MS_SILENT
);
603 /* Try to build a canonical options string. */
605 fix_opts_string (int flags
, const char *extra_opts
,
606 const char *user
, int inv_user
)
608 const struct opt_map
*om
;
609 const struct string_opt_map
*m
;
612 new_opts
= append_opt(NULL
, (flags
& MS_RDONLY
) ? "ro" : "rw", NULL
);
613 for (om
= opt_map
; om
->opt
!= NULL
; om
++) {
616 if (om
->inv
|| !om
->mask
|| (flags
& om
->mask
) != om
->mask
)
618 if (om
->mask
== MS_COMMENT
&& !(comment_flags
& om
->cmask
))
620 new_opts
= append_opt(new_opts
, om
->opt
, NULL
);
623 for (m
= &string_opt_map
[0]; m
->tag
; m
++) {
624 if (!m
->skip
&& *(m
->valptr
))
625 new_opts
= append_opt(new_opts
, m
->tag
, *(m
->valptr
));
627 if (extra_opts
&& *extra_opts
)
628 new_opts
= append_opt(new_opts
, extra_opts
, NULL
);
631 new_opts
= append_opt(new_opts
, "user=", user
);
634 for (om
= opt_map
; om
->opt
!= NULL
; om
++) {
635 if (om
->mask
&& om
->inv
636 && (inv_user
& om
->mask
) == om
->mask
) {
637 new_opts
= append_opt(new_opts
, om
->opt
, NULL
);
638 inv_user
&= ~om
->mask
;
647 already (const char *spec0
, const char *node0
) {
648 struct mntentchn
*mc
;
650 char *spec
= canonicalize_spec(spec0
);
651 char *node
= canonicalize(node0
);
653 if ((mc
= getmntfile(node
)) != NULL
)
654 error (_("mount: according to mtab, "
655 "%s is already mounted on %s"),
656 mc
->m
.mnt_fsname
, node
);
657 else if (spec
&& strcmp (spec
, "none") &&
658 (mc
= getmntfile(spec
)) != NULL
)
659 error (_("mount: according to mtab, %s is mounted on %s"),
660 spec
, mc
->m
.mnt_dir
);
670 /* Create mtab with a root entry. */
673 struct mntentchn
*fstab
;
674 struct my_mntent mnt
;
680 mfp
= my_setmntent (_PATH_MOUNTED
, "a+");
681 if (mfp
== NULL
|| mfp
->mntent_fp
== NULL
) {
683 die (EX_FILEIO
, _("mount: can't open %s for writing: %s"),
684 _PATH_MOUNTED
, strerror (errsv
));
687 /* Find the root entry by looking it up in fstab */
688 if ((fstab
= getfs_by_dir ("/")) || (fstab
= getfs_by_dir ("root"))) {
690 parse_opts (fstab
->m
.mnt_opts
, &flags
, &extra_opts
);
692 mnt
.mnt_fsname
= spec_to_devname(fstab
->m
.mnt_fsname
);
693 mnt
.mnt_type
= fstab
->m
.mnt_type
;
694 mnt
.mnt_opts
= fix_opts_string (flags
, extra_opts
, NULL
, 0);
695 mnt
.mnt_freq
= mnt
.mnt_passno
= 0;
698 if (my_addmntent (mfp
, &mnt
) == 1) {
700 die (EX_FILEIO
, _("mount: error writing %s: %s"),
701 _PATH_MOUNTED
, strerror (errsv
));
704 if (fchmod (fileno (mfp
->mntent_fp
), 0644) < 0)
705 if (errno
!= EROFS
) {
708 _("mount: error changing mode of %s: %s"),
709 _PATH_MOUNTED
, strerror (errsv
));
718 /* count successful mount system calls */
719 static int mountcount
= 0;
723 * Mount a single file system. Keep track of successes.
724 * returns: 0: OK, -1: error in errno
727 do_mount_syscall (struct mountargs
*args
) {
728 int flags
= args
->flags
;
730 if ((flags
& MS_MGC_MSK
) == 0)
734 printf("mount: mount(2) syscall: source: \"%s\", target: \"%s\", "
735 "filesystemtype: \"%s\", mountflags: %d, data: %s\n",
736 args
->spec
, args
->node
, args
->type
, flags
, (char *) args
->data
);
738 return mount (args
->spec
, args
->node
, args
->type
, flags
, args
->data
);
743 * Mount a single file system, possibly invoking an external handler to
744 * do so. Keep track of successes.
745 * returns: 0: OK, -1: error in errno
748 do_mount (struct mountargs
*args
, int *special
, int *status
) {
750 if (check_special_mountprog(args
->spec
, args
->node
, args
->type
,
751 args
->flags
, args
->data
, status
)) {
755 ret
= do_mount_syscall(args
);
763 * check_special_mountprog()
764 * If there is a special mount program for this type, exec it.
765 * returns: 0: no exec was done, 1: exec was done, status has result
768 check_special_mountprog(const char *spec
, const char *node
, const char *type
, int flags
,
769 char *extra_opts
, int *status
) {
770 char search_path
[] = FS_SEARCH_PATH
;
771 char *path
, mountprog
[150];
775 if (!external_allowed
)
778 if (type
== NULL
|| strcmp(type
, "none") == 0)
781 path
= strtok(search_path
, ":");
785 res
= snprintf(mountprog
, sizeof(mountprog
), "%s/mount.%s",
787 path
= strtok(NULL
, ":");
788 if (res
< 0 || (size_t) res
>= sizeof(mountprog
))
791 res
= stat(mountprog
, &statbuf
);
792 if (res
== -1 && errno
== ENOENT
&& strchr(type
, '.')) {
793 /* If type ends with ".subtype" try without it */
794 *strrchr(mountprog
, '.') = '\0';
796 res
= stat(mountprog
, &statbuf
);
805 case 0: { /* child */
806 char *oo
, *mountargs
[12];
809 if (setgid(getgid()) < 0)
810 die(EX_FAIL
, _("mount: cannot set group id: %m"));
812 if (setuid(getuid()) < 0)
813 die(EX_FAIL
, _("mount: cannot set user id: %m"));
815 oo
= fix_opts_string(flags
, extra_opts
, NULL
, invuser_flags
);
816 mountargs
[i
++] = mountprog
; /* 1 */
817 mountargs
[i
++] = (char *) spec
; /* 2 */
818 mountargs
[i
++] = (char *) node
; /* 3 */
819 if (sloppy
&& strncmp(type
, "nfs", 3) == 0)
820 mountargs
[i
++] = "-s"; /* 4 */
822 mountargs
[i
++] = "-f"; /* 5 */
824 mountargs
[i
++] = "-n"; /* 6 */
826 mountargs
[i
++] = "-v"; /* 7 */
828 mountargs
[i
++] = "-o"; /* 8 */
829 mountargs
[i
++] = oo
; /* 9 */
832 mountargs
[i
++] = "-t"; /* 10 */
833 mountargs
[i
++] = (char *) type
; /* 11 */
835 mountargs
[i
] = NULL
; /* 12 */
839 while (mountargs
[i
]) {
840 printf("mount: external mount: argv[%d] = \"%s\"\n",
847 execv(mountprog
, mountargs
);
848 exit(1); /* exec failed */
851 default: { /* parent */
854 *status
= (WIFEXITED(st
) ? WEXITSTATUS(st
) : EX_SYSERR
);
858 case -1: { /* error */
860 error(_("mount: cannot fork: %s"), strerror(errsv
));
869 /* list of already tested filesystems by procfsloop_mount() */
870 static struct tried
{
876 was_tested(const char *fstype
) {
879 for (t
= tried
; t
; t
= t
->next
) {
880 if (!strcmp(t
->type
, fstype
))
887 set_tested(const char *fstype
) {
888 struct tried
*t
= xmalloc(sizeof(struct tried
));
891 t
->type
= xstrdup(fstype
);
897 struct tried
*t
, *tt
;
910 procfsnext(FILE *procfs
) {
914 while (fgets(line
, sizeof(line
), procfs
)) {
915 if (sscanf (line
, "nodev %[^#\n]\n", fsname
) == 1) continue;
916 if (sscanf (line
, " %[^# \n]\n", fsname
) != 1) continue;
917 return xstrdup(fsname
);
922 /* Only use /proc/filesystems here, this is meant to test what
923 the kernel knows about, so /etc/filesystems is irrelevant.
924 Return: 1: yes, 0: no, -1: cannot open procfs */
926 known_fstype_in_procfs(const char *type
)
932 procfs
= fopen(_PATH_PROC_FILESYSTEMS
, "r");
935 while ((fsname
= procfsnext(procfs
)) != NULL
)
936 if (!strcmp(fsname
, type
)) {
946 /* Try all types in FILESYSTEMS, except those in *types,
947 in case *types starts with "no" */
948 /* return: 0: OK, -1: error in errno, 1: type not found */
949 /* when 0 or -1 is returned, *types contains the type used */
950 /* when 1 is returned, *types is NULL */
952 procfsloop_mount(int (*mount_fn
)(struct mountargs
*, int *, int *),
953 struct mountargs
*args
,
955 int *special
, int *status
)
957 char *files
[2] = { _PATH_FILESYSTEMS
, _PATH_PROC_FILESYSTEMS
};
960 const char *notypes
= NULL
;
966 if (*types
&& !strncmp(*types
, "no", 2)) {
968 notypes
= (*types
) + 2;
972 /* Use _PATH_PROC_FILESYSTEMS only when _PATH_FILESYSTEMS
973 * (/etc/filesystems) does not exist. In some cases trying a
974 * filesystem that the kernel knows about on the wrong data will crash
975 * the kernel; in such cases _PATH_FILESYSTEMS can be used to list the
976 * filesystems that we are allowed to try, and in the order they should
977 * be tried. End _PATH_FILESYSTEMS with a line containing a single '*'
978 * only, if _PATH_PROC_FILESYSTEMS should be tried afterwards.
980 for (i
=0; i
<2; i
++) {
981 procfs
= fopen(files
[i
], "r");
984 while ((fsname
= procfsnext(procfs
)) != NULL
) {
985 if (!strcmp(fsname
, "*")) {
989 if (was_tested (fsname
))
991 if (no
&& matching_type(fsname
, notypes
))
996 printf(_("Trying %s\n"), fsname
);
997 if ((*mount_fn
) (args
, special
, status
) == 0) {
1001 } else if (errno
!= EINVAL
&&
1002 known_fstype_in_procfs(fsname
) == 1) {
1019 guess_fstype_by_devname(const char *devname
, int *ambivalent
)
1021 const char *type
= fsprobe_get_fstype_by_devname_ambi(devname
, ambivalent
);
1024 printf (_("mount: you didn't specify a filesystem type for %s\n"), devname
);
1027 printf (_(" I will try all types mentioned in %s or %s\n"),
1028 _PATH_FILESYSTEMS
, _PATH_PROC_FILESYSTEMS
);
1029 else if (!strcmp(type
, MNTTYPE_SWAP
))
1030 printf (_(" and it looks like this is swapspace\n"));
1032 printf (_(" I will try type %s\n"), type
);
1038 * guess_fstype_and_mount()
1039 * Mount a single file system. Guess the type when unknown.
1040 * returns: 0: OK, -1: error in errno, 1: other error
1041 * don't exit on non-fatal errors.
1042 * on return types is filled with the type used.
1045 guess_fstype_and_mount(const char *spec
, const char *node
, const char **types
,
1046 int flags
, char *mount_opts
, int *special
, int *status
) {
1047 struct mountargs args
= { spec
, node
, NULL
, flags
& ~MS_NOSYS
, mount_opts
};
1050 if (*types
&& strcasecmp (*types
, "auto") == 0)
1053 if (!*types
&& !(flags
& MS_REMOUNT
)) {
1054 *types
= guess_fstype_by_devname(spec
, &ambivalent
);
1056 if (!strcmp(*types
, MNTTYPE_SWAP
)) {
1057 error(_("%s looks like swapspace - not mounted"), spec
);
1062 return do_mount (&args
, special
, status
);
1064 } else if (ambivalent
) {
1065 error(_("mount: %s: more filesystems detected. This should not happen,\n"
1066 " use -t <type> to explicitly specify the filesystem type or\n"
1067 " use wipefs(8) to clean up the device.\n"), spec
);
1072 /* Accept a comma-separated list of types, and try them one by one */
1073 /* A list like "nonfs,.." indicates types not to use */
1074 if (*types
&& strncmp(*types
, "no", 2) && strchr(*types
,',')) {
1075 char *t
= strdup(*types
);
1078 while((p
= strchr(t
,',')) != NULL
) {
1080 args
.type
= *types
= t
;
1081 if (do_mount (&args
, special
, status
) == 0)
1085 /* do last type below */
1089 if (*types
|| (flags
& MS_REMOUNT
)) {
1091 return do_mount (&args
, special
, status
);
1094 return procfsloop_mount(do_mount
, &args
, types
, special
, status
);
1098 * restricted_check()
1099 * Die if the user is not allowed to do this.
1102 restricted_check(const char *spec
, const char *node
, int *flags
, char **user
) {
1105 * MS_OWNER: Allow owners to mount when fstab contains
1106 * the owner option. Note that this should never be used
1107 * in a high security environment, but may be useful to give
1108 * people at the console the possibility of mounting a floppy.
1109 * MS_GROUP: Allow members of device group to mount. (Martin Dickopp)
1111 if (*flags
& (MS_OWNER
| MS_GROUP
)) {
1114 if (!strncmp(spec
, "/dev/", 5) && stat(spec
, &sb
) == 0) {
1116 if (*flags
& MS_OWNER
) {
1117 if (getuid() == sb
.st_uid
)
1121 if (*flags
& MS_GROUP
) {
1122 if (getgid() == sb
.st_gid
)
1125 int n
= getgroups(0, NULL
);
1128 gid_t
*groups
= xmalloc(n
* sizeof(*groups
));
1129 if (getgroups(n
, groups
) == n
) {
1131 for (i
= 0; i
< n
; i
++) {
1132 if (groups
[i
] == sb
.st_gid
) {
1145 /* James Kehl <mkehl@gil.com.au> came with a similar patch:
1146 allow an arbitrary user to mount when he is the owner of
1147 the mount-point and has write-access to the device.
1148 This is even less secure. Let me skip it for the time being;
1149 there should be an explicit fstab line allowing such things. */
1151 if (!(*flags
& (MS_USER
| MS_USERS
))) {
1152 if (already (spec
, node
))
1153 die (EX_USAGE
, _("mount failed"));
1155 die (EX_USAGE
, _("mount: only root can mount %s on %s"), spec
, node
);
1157 if (*flags
& MS_USER
)
1158 *user
= getusername();
1161 *flags
&= ~(MS_OWNER
| MS_GROUP
);
1164 /* Check, if there already exists a mounted loop device on the mountpoint node
1165 * with the same parameters.
1168 is_mounted_same_loopfile(const char *node0
, const char *loopfile
, unsigned long long offset
)
1170 struct mntentchn
*mnt
= NULL
;
1174 node
= canonicalize(node0
);
1176 /* Search for mountpoint node in mtab,
1177 * procceed if any of these has the loop option set or
1178 * the device is a loop device
1180 mnt
= getmntdirbackward(node
, mnt
);
1185 for(; mnt
&& res
== 0; mnt
= getmntdirbackward(node
, mnt
)) {
1188 if (strncmp(mnt
->m
.mnt_fsname
, "/dev/loop", 9) == 0)
1189 res
= loopdev_is_used((char *) mnt
->m
.mnt_fsname
,
1190 loopfile
, offset
, LOOPDEV_FL_OFFSET
);
1192 else if (mnt
->m
.mnt_opts
&&
1193 (p
= strstr(mnt
->m
.mnt_opts
, "loop=")))
1195 char *dev
= xstrdup(p
+5);
1196 if ((p
= strchr(dev
, ',')))
1198 res
= loopdev_is_used(dev
,
1199 loopfile
, offset
, LOOPDEV_FL_OFFSET
);
1209 parse_offset(const char **opt
, uintmax_t *val
)
1213 if (strtosize(*opt
, val
))
1217 snprintf(tmp
, 32, "%jd", *val
);
1224 loop_check(const char **spec
, const char **type
, int *flags
,
1225 int *loop
, const char **loopdev
, const char **loopfile
,
1228 uintmax_t offset
= 0, sizelimit
= 0;
1229 struct loopdev_cxt lc
;
1234 * In the case of a loop mount, either type is of the form lo@/dev/loop5
1235 * or the option "-o loop=/dev/loop5" or just "-o loop" is given, or
1236 * mount just has to figure things out for itself from the fact that
1237 * spec is not a block device. We do not test for a block device
1238 * immediately: maybe later other types of mountable objects will occur.
1241 *loopdev
= opt_loopdev
;
1243 looptype
= (*type
&& strncmp("lo@", *type
, 3) == 0);
1246 error(_("mount: loop device specified twice"));
1247 *loopdev
= *type
+ 3;
1248 *type
= opt_vfstype
;
1249 } else if (opt_vfstype
) {
1251 error(_("mount: type specified twice"));
1253 *type
= opt_vfstype
;
1256 *loop
= ((*flags
& MS_LOOP
) || *loopdev
|| opt_offset
|| opt_sizelimit
|| opt_encryption
);
1259 /* Automatically create a loop device from a regular file if a filesystem
1260 * is not specified or the filesystem is known for libblkid (these
1261 * filesystems work with block devices only).
1263 * Note that there is not a restriction (on kernel side) that prevents regular
1264 * file as a mount(2) source argument. A filesystem that is able to mount
1265 * regular files could be implemented.
1267 if (!*loop
&& !(*flags
& (MS_BIND
| MS_MOVE
| MS_PROPAGATION
)) &&
1268 (!*type
|| strcmp(*type
, "auto") == 0 || fsprobe_known_fstype(*type
))) {
1271 if (stat(*loopfile
, &st
) == 0)
1272 *loop
= S_ISREG(st
.st_mode
);
1279 printf(_("mount: skipping the setup of a loop device\n"));
1283 /* since 2.6.37 we don't have to store backing filename to mtab
1284 * because kernel provides the name in /sys
1286 if (get_linux_version() >= KERNEL_VERSION(2, 6, 37) ||
1287 mtab_is_writable() == 0) {
1290 printf(_("mount: enabling autoclear loopdev flag\n"));
1291 loop_opts
= LO_FLAGS_AUTOCLEAR
;
1294 if (*flags
& MS_RDONLY
)
1295 loop_opts
|= LO_FLAGS_READ_ONLY
;
1297 if (opt_offset
&& parse_offset(&opt_offset
, &offset
)) {
1298 error(_("mount: invalid offset '%s' specified"), opt_offset
);
1301 if (opt_sizelimit
&& parse_offset(&opt_sizelimit
, &sizelimit
)) {
1302 error(_("mount: invalid sizelimit '%s' specified"), opt_sizelimit
);
1306 if (is_mounted_same_loopfile(node
, *loopfile
, offset
)) {
1307 error(_("mount: according to mtab %s is already mounted on %s as loop"), *loopfile
, node
);
1311 if (opt_encryption
) {
1313 if (mlockall(MCL_CURRENT
| MCL_FUTURE
)) {
1314 error(_("mount: couldn't lock into memory"));
1318 pwd
= xgetpass(pfd
, _("Password: "));
1321 loopcxt_init(&lc
, 0);
1322 /*loopcxt_enable_debug(&lc, 1);*/
1324 if (*loopdev
&& **loopdev
)
1325 loopcxt_set_device(&lc
, *loopdev
); /* use loop=<devname> */
1330 if ((!*loopdev
|| !**loopdev
) && loopcxt_find_unused(&lc
) == 0)
1331 *loopdev
= loopcxt_strdup_device(&lc
);
1334 error(_("mount: failed to found free loop device"));
1335 loopcxt_deinit(&lc
);
1336 goto err
; /* no more loop devices */
1339 printf(_("mount: going to use the loop device %s\n"), *loopdev
);
1341 rc
= loopcxt_set_backing_file(&lc
, *loopfile
);
1344 rc
= loopcxt_set_offset(&lc
, offset
);
1345 if (!rc
&& sizelimit
)
1346 rc
= loopcxt_set_sizelimit(&lc
, sizelimit
);
1347 if (!rc
&& opt_encryption
&& pwd
)
1348 loopcxt_set_encryption(&lc
, opt_encryption
, pwd
);
1350 loopcxt_set_flags(&lc
, loop_opts
);
1353 error(_("mount: %s: failed to set loopdev attributes"), *loopdev
);
1354 loopcxt_deinit(&lc
);
1358 /* setup the device */
1359 rc
= loopcxt_setup_device(&lc
);
1361 break; /* success */
1364 error(_("mount: %s: failed setting up loop device: %m"), *loopfile
);
1369 loopcxt_deinit(&lc
);
1375 printf(_("mount: stolen loop=%s ...trying again\n"), *loopdev
);
1380 error(_("mount: stolen loop=%s"), *loopdev
);
1381 loopcxt_deinit(&lc
);
1384 } while (!*loopdev
);
1387 printf(_("mount: setup loop device successfully\n"));
1390 if (loopcxt_is_readonly(&lc
))
1391 *flags
|= MS_RDONLY
;
1393 if (loopcxt_is_autoclear(&lc
))
1394 /* Prevent recording loop dev in mtab for cleanup on umount */
1397 /* We have to keep the device open until mount(2), otherwise it will
1398 * be auto-cleared by kernel (because LO_FLAGS_AUTOCLEAR) */
1399 loopcxt_set_fd(&lc
, -1, 0);
1400 loopcxt_deinit(&lc
);
1417 update_mtab_entry(const char *spec
, const char *node
, const char *type
,
1418 const char *opts
, int flags
, int freq
, int pass
) {
1419 struct my_mntent mnt
;
1421 mnt
.mnt_fsname
= is_pseudo_fs(type
) ? xstrdup(spec
) : canonicalize(spec
);
1422 mnt
.mnt_dir
= canonicalize (node
);
1423 mnt
.mnt_type
= type
;
1424 mnt
.mnt_opts
= opts
;
1425 mnt
.mnt_freq
= freq
;
1426 mnt
.mnt_passno
= pass
;
1428 /* We get chatty now rather than after the update to mtab since the
1429 mount succeeded, even if the write to /etc/mtab should fail. */
1433 if (!nomtab
&& mtab_does_not_exist()) {
1435 printf(_("mount: no %s found - creating it..\n"),
1441 if (!nomtab
&& mtab_is_writable()) {
1442 if (flags
& MS_REMOUNT
)
1443 update_mtab (mnt
.mnt_dir
, &mnt
);
1444 else if (flags
& MS_MOVE
)
1445 update_mtab(mnt
.mnt_fsname
, &mnt
);
1447 update_mtab(NULL
, &mnt
);
1449 my_free(mnt
.mnt_fsname
);
1450 my_free(mnt
.mnt_dir
);
1457 _("mount: argument to -p or --pass-fd must be a number"));
1462 cdrom_setspeed(const char *spec
) {
1463 #define CDROM_SELECT_SPEED 0x5322 /* Set the CD-ROM speed */
1466 int speed
= atoi(opt_speed
);
1468 if ((cdrom
= open(spec
, O_RDONLY
| O_NONBLOCK
)) < 0)
1470 _("mount: cannot open %s for setting speed"),
1472 if (ioctl(cdrom
, CDROM_SELECT_SPEED
, speed
) < 0)
1473 die(EX_FAIL
, _("mount: cannot set speed: %m"));
1479 * Check if @path is on read-only filesystem independently on file permissions.
1482 is_readonly(const char *path
)
1484 if (access(path
, W_OK
) == 0)
1488 if (errno
!= EACCES
)
1491 #ifdef HAVE_FUTIMENS
1493 * access(2) returns EACCES on read-only FS:
1495 * - for set-uid application if one component of the path is not
1496 * accessible for the current rUID. (Note that euidaccess(2) does not
1497 * check for EROFS at all).
1499 * - for read-write filesystem with read-only VFS node (aka -o remount,ro,bind)
1502 struct timespec times
[2];
1504 times
[0].tv_nsec
= UTIME_NOW
; /* atime */
1505 times
[1].tv_nsec
= UTIME_OMIT
; /* mtime */
1507 if (utimensat(AT_FDCWD
, path
, times
, 0) == -1)
1508 return errno
== EROFS
;
1516 * Try to mount one file system.
1518 * returns: 0: OK, EX_SYSERR, EX_FAIL, return code from nfsmount,
1519 * return status from wait
1522 try_mount_one (const char *spec0
, const char *node0
, const char *types0
,
1523 const char *opts0
, int freq
, int pass
, int ro
) {
1524 int res
= 0, status
= 0, special
= 0;
1525 int mnt5_res
= 0; /* only for gcc */
1528 char *extra_opts
; /* written in mtab */
1529 char *mount_opts
; /* actually used on system call */
1530 const char *opts
, *spec
, *node
, *types
;
1533 const char *loopdev
= 0, *loopfile
= 0;
1534 struct stat statbuf
;
1536 /* copies for freeing on exit */
1537 const char *opts1
, *spec1
, *node1
, *types1
;
1540 printf("mount: spec: \"%s\"\n", spec0
);
1541 printf("mount: node: \"%s\"\n", node0
);
1542 printf("mount: types: \"%s\"\n", types0
);
1543 printf("mount: opts: \"%s\"\n", opts0
);
1546 spec
= spec1
= xstrdup(spec0
);
1547 node
= node1
= xstrdup(node0
);
1548 types
= types1
= xstrdup(types0
);
1549 opts
= opts1
= xstrdup(opts0
);
1551 parse_opts (opts
, &flags
, &extra_opts
);
1552 mount_opts
= xstrdup(extra_opts
);
1554 /* quietly succeed for fstab entries that don't get mounted automatically */
1555 if (mount_all
&& (flags
& MS_NOAUTO
))
1558 restricted_check(spec
, node
, &flags
, &user
);
1560 /* The "mount -f" checks for for existing record in /etc/mtab (with
1561 * regular non-fake mount this is usually done by kernel)
1563 if (!(flags
& MS_REMOUNT
) && fake
&& mounted (spec
, node
, NULL
))
1564 die(EX_USAGE
, _("mount: according to mtab, "
1565 "%s is already mounted on %s\n"),
1569 cdrom_setspeed(spec
);
1571 if (!(flags
& MS_REMOUNT
)) {
1573 * Don't set up a (new) loop device if we only remount - this left
1574 * stale assignments of files to loop devices. Nasty when used for
1577 res
= loop_check(&spec
, &types
, &flags
, &loop
, &loopdev
, &loopfile
, node
);
1583 opt_loopdev
= loopdev
;
1585 if (flags
& (MS_BIND
| MS_MOVE
| MS_PROPAGATION
))
1588 #ifdef HAVE_LIBSELINUX
1589 if (flags
& MS_REMOUNT
) {
1591 * Linux kernel does not accept any selinux context option on remount
1594 char *tmp
= mount_opts
;
1595 mount_opts
= remove_context_options(mount_opts
);
1599 } else if (types
&& strcmp(types
, "tmpfs") == 0 && is_selinux_enabled() > 0 &&
1600 !has_context_option(mount_opts
)) {
1602 * Add rootcontext= mount option for tmpfs
1603 * https://bugzilla.redhat.com/show_bug.cgi?id=476964
1605 security_context_t sc
= NULL
;
1607 if (getfilecon(node
, &sc
) > 0 && strcmp("unlabeled", sc
))
1608 append_context("rootcontext=", (char *) sc
, &mount_opts
);
1614 * Call mount.TYPE for types that require a separate mount program.
1615 * For the moment these types are ncpfs and smbfs. Maybe also vxfs.
1616 * All such special things must occur isolated in the types string.
1618 if (check_special_mountprog(spec
, node
, types
, flags
, mount_opts
, &status
)) {
1623 block_signals (SIG_BLOCK
);
1626 mnt5_res
= guess_fstype_and_mount (spec
, node
, &types
, flags
& ~MS_NOSYS
,
1627 mount_opts
, &special
, &status
);
1630 block_signals (SIG_UNBLOCK
);
1636 /* Kernel allows to use MS_RDONLY for bind mounts, but the read-only request
1637 * could be silently ignored. Check it to avoid 'ro' in mtab and 'rw' in
1640 if (!fake
&& mnt5_res
== 0 &&
1641 (flags
& MS_BIND
) && (flags
& MS_RDONLY
) && !is_readonly(node
)) {
1643 printf(_("mount: warning: %s seems to be mounted read-write.\n"), node
);
1644 flags
&= ~MS_RDONLY
;
1647 /* Kernel can silently add MS_RDONLY flag when mounting file system that
1648 * does not have write support. Check this to avoid 'ro' in /proc/mounts
1651 if (!fake
&& mnt5_res
== 0 &&
1652 !(flags
& (MS_RDONLY
| MS_PROPAGATION
| MS_MOVE
)) &&
1653 is_readonly(node
)) {
1655 printf(_("mount: warning: %s seems to be mounted read-only.\n"), node
);
1659 if (fake
|| mnt5_res
== 0) {
1660 char *mo
= fix_opts_string (flags
& ~MS_NOMTAB
, extra_opts
, user
, 0);
1661 const char *tp
= types
? types
: "unknown";
1663 /* Mount succeeded, report this (if verbose) and write mtab entry. */
1664 if (!(mounttype
& MS_PROPAGATION
))
1665 update_mtab_entry(loop
? loopfile
: spec
,
1673 block_signals (SIG_UNBLOCK
);
1683 loopdev_delete(spec
);
1685 block_signals (SIG_UNBLOCK
);
1687 /* Mount failed, complain, but don't die. */
1691 error (_("mount: I could not determine the filesystem type, "
1692 "and none was specified"));
1694 error (_("mount: you must specify the filesystem type"));
1695 } else if (mnt5_res
!= -1) {
1696 /* should not happen */
1697 error (_("mount: mount failed"));
1701 if (geteuid() == 0) {
1702 if (stat (node
, &statbuf
) || !S_ISDIR(statbuf
.st_mode
))
1703 error (_("mount: mount point %s is not a directory"), node
);
1705 error (_("mount: permission denied"));
1707 error (_("mount: must be superuser to use mount"));
1710 if (flags
& MS_REMOUNT
) {
1711 error (_("mount: %s is busy"), node
);
1712 } else if (!strcmp(types
, "proc") && !strcmp(node
, "/proc")) {
1713 /* heuristic: if /proc/version exists, then probably proc is mounted */
1714 if (stat ("/proc/version", &statbuf
)) /* proc mounted? */
1715 error (_("mount: %s is busy"), node
); /* no */
1716 else if (!mount_all
|| verbose
) /* yes, don't mention it */
1717 error (_("mount: proc already mounted"));
1719 error (_("mount: %s already mounted or %s busy"), spec
, node
);
1720 already (spec
, node
);
1724 if (lstat (node
, &statbuf
))
1725 error (_("mount: mount point %s does not exist"), node
);
1726 else if (stat (node
, &statbuf
))
1727 error (_("mount: mount point %s is a symbolic link to nowhere"),
1729 else if (stat (spec
, &statbuf
)) {
1732 error (_("mount: special device %s does not exist"), spec
);
1739 if (stat (node
, &statbuf
) || ! S_ISDIR(statbuf
.st_mode
))
1740 error (_("mount: mount point %s is not a directory"), node
);
1741 else if (stat (spec
, &statbuf
) && errno
== ENOTDIR
) {
1744 error (_("mount: special device %s does not exist\n"
1745 " (a path prefix is not a directory)\n"), spec
);
1753 unsigned long long size
= 0;
1755 if (flags
& MS_REMOUNT
) {
1756 error (_("mount: %s not mounted or bad option"), node
);
1758 error (_("mount: wrong fs type, bad option, bad superblock on %s,\n"
1759 " missing codepage or helper program, or other error"),
1762 if (stat(spec
, &statbuf
) < 0) {
1763 if (errno
== ENOENT
) /* network FS? */
1765 " (for several filesystems (e.g. nfs, cifs) you might\n"
1766 " need a /sbin/mount.<type> helper program)"));
1768 } else if (S_ISBLK(statbuf
.st_mode
)
1769 && (fd
= open(spec
, O_RDONLY
| O_NONBLOCK
)) >= 0) {
1771 if (blkdev_get_size(fd
, &size
) == 0) {
1772 if (size
== 0 && !loop
)
1774 " (could this be the IDE device where you in fact use\n"
1775 " ide-scsi so that sr0 or sda or so is needed?)"));
1777 if (size
&& size
<= 2)
1779 " (aren't you trying to mount an extended partition,\n"
1780 " instead of some logical partition inside?)"));
1786 " In some cases useful info is found in syslog - try\n"
1787 " dmesg | tail or so\n"));
1792 error (_("mount table full")); break;
1794 error (_("mount: %s: can't read superblock"), spec
); break;
1797 int pfs
= known_fstype_in_procfs(types
);
1799 if (pfs
== 1 || !strcmp(types
, "guess"))
1800 error(_("mount: %s: unknown device"), spec
);
1801 else if (pfs
== 0) {
1805 error (_("mount: unknown filesystem type '%s'"), types
);
1807 /* maybe this loser asked for FAT or ISO9660 or isofs */
1808 lowtype
= xstrdup(types
);
1810 for(p
=lowtype
; *p
; p
++) {
1811 if(tolower(*p
) != *p
) {
1816 if (u
&& known_fstype_in_procfs(lowtype
) == 1)
1817 error (_("mount: probably you meant %s"), lowtype
);
1818 else if (!strncmp(lowtype
, "iso", 3) &&
1819 known_fstype_in_procfs("iso9660") == 1)
1820 error (_("mount: maybe you meant 'iso9660'?"));
1821 else if (!strncmp(lowtype
, "fat", 3) &&
1822 known_fstype_in_procfs("vfat") == 1)
1823 error (_("mount: maybe you meant 'vfat'?"));
1826 error (_("mount: %s has wrong device number or fs type %s not supported"),
1833 if (stat (spec
, &statbuf
)) /* strange ... */
1834 error (_("mount: %s is not a block device, and stat fails?"), spec
);
1835 else if (S_ISBLK(statbuf
.st_mode
))
1836 error (_("mount: the kernel does not recognize %s as a block device\n"
1837 " (maybe `modprobe driver'?)"), spec
);
1838 else if (S_ISREG(statbuf
.st_mode
))
1839 error (_("mount: %s is not a block device (maybe try `-o loop'?)"),
1842 error (_("mount: %s is not a block device"), spec
);
1847 error (_("mount: %s is not a valid block device"), spec
); break;
1848 case EACCES
: /* pre-linux 1.1.38, 1.1.41 and later */
1849 case EROFS
: /* linux 1.1.38 and later */
1850 { char *bd
= (loop
? "" : _("block device "));
1851 if (ro
|| (flags
& MS_RDONLY
)) {
1852 error (_("mount: cannot mount %s%s read-only"),
1855 } else if (readwrite
) {
1856 error (_("mount: %s%s is write-protected but explicit `-w' flag given"),
1859 } else if (flags
& MS_REMOUNT
) {
1860 error (_("mount: cannot remount %s%s read-write, is write-protected"),
1868 char *opts2
= append_opt(xstrdup(opts
), "ro", NULL
);
1870 opts
= opts1
= opts2
;
1873 if (types
&& !strcmp(types
, "guess"))
1875 error (_("mount: %s%s is write-protected, mounting read-only"),
1877 res
= try_mount_one (spec0
, node0
, types
, opts
, freq
, pass
, 1);
1883 error(_("mount: no medium found on %s"), spec
);
1886 error ("mount: %s", strerror (mnt_err
)); break;
1893 #if defined(HAVE_LIBSELINUX) && defined(HAVE_SECURITY_GET_INITIAL_CONTEXT)
1894 if (res
!= EX_FAIL
&& verbose
&& is_selinux_enabled() > 0) {
1895 security_context_t raw
= NULL
, def
= NULL
;
1897 if (getfilecon(node
, &raw
) > 0 &&
1898 security_get_initial_context("file", &def
) == 0) {
1900 if (!selinux_file_context_cmp(raw
, def
))
1901 printf(_("mount: %s does not contain SELinux labels.\n"
1902 " You just mounted an file system that supports labels which does not\n"
1903 " contain labels, onto an SELinux box. It is likely that confined\n"
1904 " applications will generate AVC messages and not be allowed access to\n"
1905 " this file system. For more details see restorecon(8) and mount(8).\n"),
1913 my_free(mount_opts
);
1914 my_free(extra_opts
);
1924 subst_string(const char *s
, const char *sub
, int sublen
, const char *repl
) {
1927 n
= (char *) xmalloc(strlen(s
)-sublen
+strlen(repl
)+1);
1928 strncpy (n
, s
, sub
-s
);
1929 strcpy (n
+ (sub
-s
), repl
);
1930 strcat (n
, sub
+sublen
);
1935 usersubst(const char *opts
) {
1943 if (opts
&& (w
= strstr(opts
, s
)) != NULL
) {
1944 sprintf(id
, "uid=%u", getuid());
1945 opts
= subst_string(opts
, w
, strlen(s
), id
);
1948 if (opts
&& (w
= strstr(opts
, s
)) != NULL
) {
1949 sprintf(id
, "gid=%u", getgid());
1950 opts
= subst_string(opts
, w
, strlen(s
), id
);
1952 return xstrdup(opts
);
1956 is_existing_file (const char *s
) {
1957 struct stat statbuf
;
1959 return (stat(s
, &statbuf
) == 0);
1963 * Return 0 for success (either mounted sth or -a and NOAUTO was given)
1966 mount_one (const char *spec
, const char *node
, const char *types
,
1967 const char *fstabopts
, char *cmdlineopts
, int freq
, int pass
) {
1968 const char *nspec
= NULL
;
1971 /* Substitute values in opts, if required */
1972 opts
= usersubst(fstabopts
);
1974 /* Merge the fstab and command line options. */
1975 opts
= append_opt(opts
, cmdlineopts
, NULL
);
1977 if (types
== NULL
&& !mounttype
&& !is_existing_file(spec
)) {
1978 if (strchr (spec
, ':') != NULL
) {
1981 printf(_("mount: no type was given - "
1982 "I'll assume nfs because of "
1984 } else if(!strncmp(spec
, "//", 2)) {
1987 printf(_("mount: no type was given - "
1988 "I'll assume cifs because of "
1989 "the // prefix\n"));
1993 /* Handle possible LABEL= and UUID= forms of spec */
1994 if (types
== NULL
|| (strncmp(types
, "9p", 2) &&
1995 strncmp(types
, "nfs", 3) &&
1996 strncmp(types
, "cifs", 4) &&
1997 strncmp(types
, "smbfs", 5))) {
1998 if (!is_pseudo_fs(types
))
1999 nspec
= spec_to_devname(spec
);
2004 return try_mount_one (spec
, node
, types
, opts
, freq
, pass
, 0);
2008 mounted (const char *spec0
, const char *node0
,
2009 struct mntentchn
*fstab_mc
__attribute__((__unused__
))) {
2011 struct mntentchn
*mc
, *mc0
;
2012 const char *spec
, *node
;
2015 /* Handle possible UUID= and LABEL= in spec */
2016 spec
= spec_to_devname(spec0
);
2020 node
= canonicalize(node0
);
2024 for (mc
= mc0
->nxt
; mc
&& mc
!= mc0
; mc
= mc
->nxt
)
2025 if (streq (spec
, mc
->m
.mnt_fsname
) &&
2026 streq (node
, mc
->m
.mnt_dir
)) {
2037 /* returns 0 if not mounted, 1 if mounted and -1 in case of error */
2039 is_fstab_entry_mounted(struct mntentchn
*mc
, int verbose
)
2043 if (mounted(mc
->m
.mnt_fsname
, mc
->m
.mnt_dir
, mc
))
2046 /* extra care for loop devices */
2047 if ((mc
->m
.mnt_opts
&& strstr(mc
->m
.mnt_opts
, "loop=")) ||
2048 (stat(mc
->m
.mnt_fsname
, &st
) == 0 && S_ISREG(st
.st_mode
))) {
2050 char *p
= get_option_value(mc
->m
.mnt_opts
, "offset=");
2051 uintmax_t offset
= 0;
2053 if (p
&& strtosize(p
, &offset
) != 0) {
2055 printf(_("mount: ignore %s "
2056 "(unparsable offset= option)\n"),
2061 if (is_mounted_same_loopfile(mc
->m
.mnt_dir
, mc
->m
.mnt_fsname
, offset
))
2068 printf(_("mount: %s already mounted on %s\n"),
2069 mc
->m
.mnt_fsname
, mc
->m
.mnt_dir
);
2073 /* avoid using stat() on things we are not going to mount anyway.. */
2075 has_noauto (const char *opts
) {
2080 s
= strstr(opts
, "noauto");
2083 return (s
== opts
|| s
[-1] == ',') && (s
[6] == 0 || s
[6] == ',');
2086 /* Mount all filesystems of the specified types except swap and root. */
2087 /* With the --fork option: fork and let different incarnations of
2088 mount handle different filesystems. However, try to avoid several
2089 simultaneous mounts on the same physical disk, since that is very slow. */
2090 #define DISKMAJOR(m) (((int) m) & ~0xf)
2093 do_mount_all (char *types
, char *options
, char *test_opts
) {
2094 struct mntentchn
*mc
, *mc0
, *mtmp
;
2096 struct stat statbuf
;
2100 struct mntentchn
*mec
;
2101 struct mntentchn
*meclast
;
2103 } childhead
, *childtail
, *cp
;
2107 /* build a chain of what we have to do, or maybe
2108 several chains, one for each major or NFS host */
2110 childtail
= &childhead
;
2112 for (mc
= mc0
->nxt
; mc
&& mc
!= mc0
; mc
= mc
->nxt
) {
2113 if (has_noauto (mc
->m
.mnt_opts
))
2115 if (matching_type (mc
->m
.mnt_type
, types
)
2116 && matching_opts (mc
->m
.mnt_opts
, test_opts
)
2117 && !streq (mc
->m
.mnt_dir
, "/")
2118 && !streq (mc
->m
.mnt_dir
, "root")
2119 && !is_fstab_entry_mounted(mc
, verbose
)) {
2121 mtmp
= (struct mntentchn
*) xmalloc(sizeof(*mtmp
));
2126 if (stat(mc
->m
.mnt_fsname
, &statbuf
) == 0 &&
2127 S_ISBLK(statbuf
.st_mode
)) {
2128 sprintf(major
, "#%x",
2129 DISKMAJOR(statbuf
.st_rdev
));
2132 if (strcmp(mc
->m
.mnt_type
, "nfs") == 0) {
2133 g
= xstrdup(mc
->m
.mnt_fsname
);
2134 colon
= strchr(g
, ':');
2140 for (cp
= childhead
.nxt
; cp
; cp
= cp
->nxt
)
2142 strcmp(cp
->group
, g
) == 0) {
2143 cp
->meclast
->nxt
= mtmp
;
2148 cp
= (struct child
*) xmalloc(sizeof *cp
);
2150 cp
->mec
= cp
->meclast
= mtmp
;
2151 cp
->group
= xstrdup(g
);
2153 childtail
->nxt
= cp
;
2160 /* now do everything */
2161 for (cp
= childhead
.nxt
; cp
; cp
= cp
->nxt
) {
2167 error(_("mount: cannot fork: %s"),
2174 /* if child, or not forked, do the mounting */
2175 if (p
== 0 || p
== -1) {
2176 for (mc
= cp
->mec
; mc
; mc
= mc
->nxt
) {
2177 status
|= mount_one (mc
->m
.mnt_fsname
,
2184 status
|= EX_SOMEOK
;
2190 /* wait for children, if any */
2191 while ((cp
= childhead
.nxt
) != NULL
) {
2192 childhead
.nxt
= cp
->nxt
;
2196 if(waitpid(cp
->pid
, &ret
, 0) == -1) {
2200 } else if (WIFEXITED(ret
))
2201 status
|= WEXITSTATUS(ret
);
2203 status
|= EX_SYSERR
;
2207 status
|= EX_SOMEOK
;
2211 static struct option longopts
[] = {
2212 { "all", 0, 0, 'a' },
2213 { "fake", 0, 0, 'f' },
2214 { "fork", 0, 0, 'F' },
2215 { "help", 0, 0, 'h' },
2216 { "no-mtab", 0, 0, 'n' },
2217 { "read-only", 0, 0, 'r' },
2218 { "ro", 0, 0, 'r' },
2219 { "verbose", 0, 0, 'v' },
2220 { "version", 0, 0, 'V' },
2221 { "read-write", 0, 0, 'w' },
2222 { "rw", 0, 0, 'w' },
2223 { "options", 1, 0, 'o' },
2224 { "test-opts", 1, 0, 'O' },
2225 { "pass-fd", 1, 0, 'p' },
2226 { "types", 1, 0, 't' },
2227 { "bind", 0, 0, 'B' },
2228 { "move", 0, 0, 'M' },
2229 { "guess-fstype", 1, 0, 134 },
2230 { "rbind", 0, 0, 'R' },
2231 { "make-shared", 0, 0, 136 },
2232 { "make-slave", 0, 0, 137 },
2233 { "make-private", 0, 0, 138 },
2234 { "make-unbindable", 0, 0, 139 },
2235 { "make-rshared", 0, 0, 140 },
2236 { "make-rslave", 0, 0, 141 },
2237 { "make-rprivate", 0, 0, 142 },
2238 { "make-runbindable", 0, 0, 143 },
2239 { "no-canonicalize", 0, 0, 144 },
2240 { "internal-only", 0, 0, 'i' },
2244 /* Keep the usage message at max 22 lines, each at most 70 chars long.
2245 The user should not need a pager to read it. */
2247 usage (FILE *fp
, int n
) {
2249 "Usage: mount -V : print version\n"
2250 " mount -h : print this help\n"
2251 " mount : list mounted filesystems\n"
2252 " mount -l : idem, including volume labels\n"
2253 "So far the informational part. Next the mounting.\n"
2254 "The command is `mount [-t fstype] something somewhere'.\n"
2255 "Details found in /etc/fstab may be omitted.\n"
2256 " mount -a [-t|-O] ... : mount all stuff from /etc/fstab\n"
2257 " mount device : mount device at the known place\n"
2258 " mount directory : mount known device here\n"
2259 " mount -t type dev dir : ordinary mount command\n"
2260 "Note that one does not really mount a device, one mounts\n"
2261 "a filesystem (of the given type) found on the device.\n"
2262 "One can also mount an already visible directory tree elsewhere:\n"
2263 " mount --bind olddir newdir\n"
2264 "or move a subtree:\n"
2265 " mount --move olddir newdir\n"
2266 "One can change the type of mount containing the directory dir:\n"
2267 " mount --make-shared dir\n"
2268 " mount --make-slave dir\n"
2269 " mount --make-private dir\n"
2270 " mount --make-unbindable dir\n"
2271 "One can change the type of all the mounts in a mount subtree\n"
2272 "containing the directory dir:\n"
2273 " mount --make-rshared dir\n"
2274 " mount --make-rslave dir\n"
2275 " mount --make-rprivate dir\n"
2276 " mount --make-runbindable dir\n"
2277 "A device can be given by name, say /dev/hda1 or /dev/cdrom,\n"
2278 "or by label, using -L label or by uuid, using -U uuid .\n"
2279 "Other options: [-nfFrsvw] [-o options] [-p passwdfd].\n"
2280 "For many more details, say man 8 mount .\n"
2287 /* returns mount entry from fstab */
2288 static struct mntentchn
*
2289 getfs(const char *spec
, const char *uuid
, const char *label
)
2291 struct mntentchn
*mc
= NULL
;
2292 const char *devname
= NULL
;
2294 if (!spec
&& !uuid
&& !label
)
2298 * A) 99% of all cases, the spec on cmdline matches
2299 * with spec in fstab
2302 mc
= getfs_by_uuid(uuid
);
2304 mc
= getfs_by_label(label
);
2306 mc
= getfs_by_dir(spec
);
2309 mc
= getfs_by_spec(spec
);
2315 * B) UUID or LABEL on cmdline, but devname in fstab
2318 devname
= fsprobe_get_devname_by_uuid(uuid
);
2320 devname
= fsprobe_get_devname_by_label(label
);
2322 devname
= spec_to_devname(spec
);
2325 mc
= getfs_by_devname(devname
);
2330 if (!mc
&& devname
) {
2331 const char *id
= NULL
;
2333 if (!label
&& (!spec
|| strncmp(spec
, "LABEL=", 6))) {
2334 id
= fsprobe_get_label_by_devname(devname
);
2336 mc
= getfs_by_label(id
);
2338 if (!mc
&& !uuid
&& (!spec
|| strncmp(spec
, "UUID=", 5))) {
2339 id
= fsprobe_get_uuid_by_devname(devname
);
2341 mc
= getfs_by_uuid(id
);
2346 /* use real device name to avoid repetitional
2347 * conversion from LABEL/UUID to devname
2349 my_free(mc
->m
.mnt_fsname
);
2350 mc
->m
.mnt_fsname
= xstrdup(devname
);
2355 * D) remount -- try /etc/mtab
2356 * Earlier mtab was tried first, but this would sometimes try the
2357 * wrong mount in case mtab had the root device entry wrong. Try
2358 * the last occurrence first, since that is the visible mount.
2360 if (!mc
&& (devname
|| spec
))
2361 mc
= getmntfilebackward (devname
? devname
: spec
, NULL
);
2369 print_version(int rc
) {
2370 printf( "mount from %s (with "
2371 #ifdef HAVE_LIBBLKID
2376 #ifdef HAVE_LIBSELINUX
2379 " support)\n", PACKAGE_STRING
);
2384 main(int argc
, char *argv
[]) {
2385 int c
, result
= 0, specseen
;
2386 char *options
= NULL
, *test_opts
= NULL
, *node
;
2387 const char *spec
= NULL
;
2392 struct mntentchn
*mc
;
2396 setlocale(LC_ALL
, "");
2397 bindtextdomain(PACKAGE
, LOCALEDIR
);
2398 textdomain(PACKAGE
);
2399 atexit(close_stdout
);
2402 if ((p
= strrchr(progname
, '/')) != NULL
)
2407 /* People report that a mount called from init without console
2408 writes error messages to /etc/mtab
2409 Let us try to avoid getting fd's 0,1,2 */
2410 while((fd
= open("/dev/null", O_RDWR
)) == 0 || fd
== 1 || fd
== 2) ;
2416 #ifdef DO_PS_FIDDLING
2417 initproctitle(argc
, argv
);
2420 while ((c
= getopt_long (argc
, argv
, "aBfFhilL:Mno:O:p:rRsU:vVwt:",
2421 longopts
, NULL
)) != -1) {
2423 case 'a': /* mount everything in fstab */
2426 case 'B': /* bind */
2427 mounttype
= MS_BIND
;
2429 case 'f': /* fake: don't actually call mount(2) */
2435 case 'h': /* help */
2439 external_allowed
= 0;
2442 list_with_volumelabel
= 1;
2447 case 'M': /* move */
2448 mounttype
= MS_MOVE
;
2450 case 'n': /* do not write /etc/mtab */
2453 case 'o': /* specify mount options */
2454 options
= append_opt(options
, optarg
, NULL
);
2456 case 'O': /* with -t: mount only if (not) opt */
2457 test_opts
= append_opt(test_opts
, optarg
, NULL
);
2459 case 'p': /* fd on which to read passwd */
2462 case 'r': /* mount readonly */
2466 case 'R': /* rbind */
2467 mounttype
= (MS_BIND
| MS_REC
);
2469 case 's': /* allow sloppy mount options */
2472 case 't': /* specify file system types */
2478 case 'v': /* be chatty - more so if repeated */
2481 case 'V': /* version */
2482 print_version(EXIT_SUCCESS
);
2484 case 'w': /* mount read/write */
2492 /* undocumented, may go away again:
2493 call: mount --guess-fstype device
2494 use only for testing purposes -
2495 the guessing is not reliable at all */
2498 fstype
= fsprobe_get_fstype_by_devname(optarg
);
2499 printf("%s\n", fstype
? fstype
: "unknown");
2500 exit(fstype
? 0 : EX_FAIL
);
2504 mounttype
= MS_SHARED
;
2508 mounttype
= MS_SLAVE
;
2512 mounttype
= MS_PRIVATE
;
2516 mounttype
= MS_UNBINDABLE
;
2520 mounttype
= (MS_SHARED
| MS_REC
);
2524 mounttype
= (MS_SLAVE
| MS_REC
);
2528 mounttype
= (MS_PRIVATE
| MS_REC
);
2532 mounttype
= (MS_UNBINDABLE
| MS_REC
);
2539 usage (stderr
, EX_USAGE
);
2544 printf("mount: fstab path: \"%s\"\n", _PATH_MNTTAB
);
2545 printf("mount: mtab path: \"%s\"\n", _PATH_MOUNTED
);
2546 printf("mount: lock path: \"%s\"\n", _PATH_MOUNTED_LOCK
);
2547 printf("mount: temp path: \"%s\"\n", _PATH_MOUNTED_TMP
);
2548 printf("mount: UID: %u\n", getuid());
2549 printf("mount: eUID: %u\n", geteuid());
2555 specseen
= (uuid
|| label
) ? 1 : 0; /* yes, .. i know */
2557 if (argc
+specseen
== 0 && !mount_all
) {
2558 if (options
|| mounttype
)
2559 usage (stderr
, EX_USAGE
);
2560 return print_all (types
);
2564 const uid_t ruid
= getuid();
2565 const uid_t euid
= geteuid();
2567 /* if we're really root and aren't running setuid */
2568 if (((uid_t
)0 == ruid
) && (ruid
== euid
)) {
2573 (types
|| options
|| readwrite
|| nomtab
|| mount_all
||
2574 nocanonicalize
|| fake
|| mounttype
||
2575 (argc
+ specseen
) != 1)) {
2577 if (ruid
== 0 && euid
!= 0)
2578 /* user is root, but setuid to non-root */
2579 die (EX_USAGE
, _("mount: only root can do that "
2580 "(effective UID is %u)"), euid
);
2582 die (EX_USAGE
, _("mount: only root can do that"));
2586 atexit(unlock_mtab
);
2588 switch (argc
+specseen
) {
2591 result
= do_mount_all (types
, options
, test_opts
);
2592 if (result
== 0 && verbose
&& !fake
)
2593 error(_("nothing was mounted"));
2597 /* mount [-nfrvw] [-o options] special | node
2598 * mount -L label (or -U uuid)
2599 * (/etc/fstab is necessary)
2602 usage (stderr
, EX_USAGE
);
2605 mc
= getfs(NULL
, uuid
, label
);
2607 mc
= getfs(*argv
, NULL
, NULL
);
2611 die (EX_USAGE
, _("mount: no such partition found"));
2614 _("mount: can't find %s in %s or %s"),
2615 *argv
, _PATH_MNTTAB
, _PATH_MOUNTED
);
2618 result
= mount_one (xstrdup (mc
->m
.mnt_fsname
),
2619 xstrdup (mc
->m
.mnt_dir
),
2620 xstrdup (mc
->m
.mnt_type
),
2621 mc
->m
.mnt_opts
, options
, 0, 0);
2625 /* mount special node (/etc/fstab is not necessary) */
2627 /* mount -L label node (or -U uuid) */
2628 spec
= uuid
? fsprobe_get_devname_by_uuid(uuid
) :
2629 fsprobe_get_devname_by_label(label
);
2632 /* mount special node */
2637 die (EX_USAGE
, _("mount: no such partition found"));
2639 result
= mount_one (spec
, node
, types
, NULL
, options
, 0, 0);
2643 usage (stderr
, EX_USAGE
);
2646 if (result
== EX_SOMEOK
)