]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - mount/mount.c
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"
46 #define DO_PS_FIDDLING
49 #include "setproctitle.h"
52 /* True for fake mount (-f). */
55 /* True if we are allowed to call /sbin/mount.${FSTYPE} */
56 static int external_allowed
= 1;
58 /* Don't write an entry in /etc/mtab (-n). */
59 static int nomtab
= 0;
61 /* True for explicit readonly (-r). */
62 static int readonly
= 0;
64 /* Nonzero for sloppy (-s). */
65 static int sloppy
= 0;
67 /* True for explicit read/write (-w). */
68 static int readwrite
= 0;
70 /* True for all mount (-a). */
71 static int mount_all
= 0;
73 /* True for fork() during all mount (-F). */
74 static int optfork
= 0;
76 /* Add volumelabel in a listing of mounted devices (-l). */
77 static int list_with_volumelabel
= 0;
79 /* Nonzero for mount {bind|move|make-shared|make-private|
80 * make-unbindable|make-slave}
82 static int mounttype
= 0;
84 /* True if (ruid != euid) or (0 != ruid), i.e. only "user" mounts permitted. */
85 static int restricted
= 1;
87 /* Contains the fd to read the passphrase from, if any. */
90 #ifdef HAVE_LIBMOUNT_MOUNT
91 static struct libmnt_update
*mtab_update
;
92 static char *mtab_opts
;
93 static unsigned long mtab_flags
;
95 static void prepare_mtab_entry(const char *spec
, const char *node
,
96 const char *type
, const char *opts
, unsigned long flags
);
99 /* mount(2) options */
108 /* Map from -o and fstab option strings to the flag argument to mount(2). */
110 const char *opt
; /* option name */
111 int skip
; /* skip in mtab option string */
112 int inv
; /* true if flag value should be inverted */
113 int mask
; /* flag mask value */
116 /* Custom mount options for our own purposes. */
117 /* Maybe these should now be freed for kernel use again */
118 #define MS_NOAUTO 0x80000000
119 #define MS_USERS 0x40000000
120 #define MS_USER 0x20000000
121 #define MS_OWNER 0x10000000
122 #define MS_GROUP 0x08000000
123 #define MS_COMMENT 0x02000000
124 #define MS_LOOP 0x00010000
126 /* Options that we keep the mount system call from seeing. */
127 #define MS_NOSYS (MS_NOAUTO|MS_USERS|MS_USER|MS_COMMENT|MS_LOOP)
129 /* Options that we keep from appearing in the options field in the mtab. */
130 #define MS_NOMTAB (MS_REMOUNT|MS_NOAUTO|MS_USERS|MS_USER)
132 #define MS_PROPAGATION (MS_SHARED|MS_SLAVE|MS_UNBINDABLE|MS_PRIVATE)
134 /* Options that we make ordinary users have by default. */
135 #define MS_SECURE (MS_NOEXEC|MS_NOSUID|MS_NODEV)
137 /* Options that we make owner-mounted devices have by default */
138 #define MS_OWNERSECURE (MS_NOSUID|MS_NODEV)
140 static const struct opt_map opt_map
[] = {
141 { "defaults", 0, 0, 0 }, /* default options */
142 { "ro", 1, 0, MS_RDONLY
}, /* read-only */
143 { "rw", 1, 1, MS_RDONLY
}, /* read-write */
144 { "exec", 0, 1, MS_NOEXEC
}, /* permit execution of binaries */
145 { "noexec", 0, 0, MS_NOEXEC
}, /* don't execute binaries */
146 { "suid", 0, 1, MS_NOSUID
}, /* honor suid executables */
147 { "nosuid", 0, 0, MS_NOSUID
}, /* don't honor suid executables */
148 { "dev", 0, 1, MS_NODEV
}, /* interpret device files */
149 { "nodev", 0, 0, MS_NODEV
}, /* don't interpret devices */
150 { "sync", 0, 0, MS_SYNCHRONOUS
}, /* synchronous I/O */
151 { "async", 0, 1, MS_SYNCHRONOUS
}, /* asynchronous I/O */
152 { "dirsync", 0, 0, MS_DIRSYNC
}, /* synchronous directory modifications */
153 { "remount", 0, 0, MS_REMOUNT
}, /* Alter flags of mounted FS */
154 { "bind", 0, 0, MS_BIND
}, /* Remount part of tree elsewhere */
155 { "rbind", 0, 0, MS_BIND
|MS_REC
}, /* Idem, plus mounted subtrees */
156 { "auto", 0, 1, MS_NOAUTO
}, /* Can be mounted using -a */
157 { "noauto", 0, 0, MS_NOAUTO
}, /* Can only be mounted explicitly */
158 { "users", 0, 0, MS_USERS
}, /* Allow ordinary user to mount */
159 { "nousers", 0, 1, MS_USERS
}, /* Forbid ordinary user to mount */
160 { "user", 0, 0, MS_USER
}, /* Allow ordinary user to mount */
161 { "nouser", 0, 1, MS_USER
}, /* Forbid ordinary user to mount */
162 { "owner", 0, 0, MS_OWNER
}, /* Let the owner of the device mount */
163 { "noowner", 0, 1, MS_OWNER
}, /* Device owner has no special privs */
164 { "group", 0, 0, MS_GROUP
}, /* Let the group of the device mount */
165 { "nogroup", 0, 1, MS_GROUP
}, /* Device group has no special privs */
166 { "_netdev", 0, 0, MS_COMMENT
}, /* Device requires network */
167 { "comment", 0, 0, MS_COMMENT
}, /* fstab comment only (kudzu,_netdev)*/
169 /* add new options here */
171 { "sub", 0, 1, MS_NOSUB
}, /* allow submounts */
172 { "nosub", 0, 0, MS_NOSUB
}, /* don't allow submounts */
175 { "quiet", 0, 0, MS_SILENT
}, /* be quiet */
176 { "loud", 0, 1, MS_SILENT
}, /* print out messages. */
179 { "mand", 0, 0, MS_MANDLOCK
}, /* Allow mandatory locks on this FS */
180 { "nomand", 0, 1, MS_MANDLOCK
}, /* Forbid mandatory locks on this FS */
182 { "loop", 1, 0, MS_LOOP
}, /* use a loop device */
184 { "atime", 0, 1, MS_NOATIME
}, /* Update access time */
185 { "noatime", 0, 0, MS_NOATIME
}, /* Do not update access time */
188 { "iversion", 0, 0, MS_I_VERSION
}, /* Update inode I_version time */
189 { "noiversion", 0, 1, MS_I_VERSION
}, /* Don't update inode I_version time */
192 { "diratime", 0, 1, MS_NODIRATIME
}, /* Update dir access times */
193 { "nodiratime", 0, 0, MS_NODIRATIME
},/* Do not update dir access times */
196 { "relatime", 0, 0, MS_RELATIME
}, /* Update access times relative to
198 { "norelatime", 0, 1, MS_RELATIME
}, /* Update access time without regard
201 #ifdef MS_STRICTATIME
202 { "strictatime", 0, 0, MS_STRICTATIME
}, /* Strict atime semantics */
203 { "nostrictatime", 0, 1, MS_STRICTATIME
}, /* kernel default atime */
205 { "nofail", 0, 0, MS_COMMENT
}, /* Do not fail if ENOENT on dev */
209 static int opt_nofail
= 0;
211 static const char *opt_loopdev
, *opt_vfstype
, *opt_offset
, *opt_sizelimit
,
212 *opt_encryption
, *opt_speed
, *opt_comment
, *opt_uhelper
;
214 static int is_readonly(const char *node
);
215 static int mounted (const char *spec0
, const char *node0
);
216 static int check_special_mountprog(const char *spec
, const char *node
,
217 const char *type
, int flags
, char *extra_opts
, int *status
);
219 static struct string_opt_map
{
223 } string_opt_map
[] = {
224 { "loop=", 0, &opt_loopdev
},
225 { "vfs=", 1, &opt_vfstype
},
226 { "offset=", 0, &opt_offset
},
227 { "sizelimit=", 0, &opt_sizelimit
},
228 { "encryption=", 0, &opt_encryption
},
229 { "speed=", 0, &opt_speed
},
230 { "comment=", 1, &opt_comment
},
231 { "uhelper=", 0, &opt_uhelper
},
236 clear_string_opts(void) {
237 struct string_opt_map
*m
;
239 for (m
= &string_opt_map
[0]; m
->tag
; m
++)
244 parse_string_opt(char *s
) {
245 struct string_opt_map
*m
;
248 for (m
= &string_opt_map
[0]; m
->tag
; m
++) {
249 lth
= strlen(m
->tag
);
250 if (!strncmp(s
, m
->tag
, lth
)) {
251 *(m
->valptr
) = xstrdup(s
+ lth
);
258 /* Report on a single mount. */
260 print_one (const struct my_mntent
*me
) {
267 /* users assume backing file name rather than /dev/loopN in
268 * mount(8) output if the device has been initialized by mount(8).
270 if (strncmp(me
->mnt_fsname
, "/dev/loop", 9) == 0 &&
271 is_loop_autoclear(me
->mnt_fsname
))
272 fsname
= loopdev_get_loopfile(me
->mnt_fsname
);
275 fsname
= (char *) me
->mnt_fsname
;
277 printf ("%s on %s", fsname
, me
->mnt_dir
);
278 if (me
->mnt_type
!= NULL
&& *(me
->mnt_type
) != '\0')
279 printf (" type %s", me
->mnt_type
);
280 if (me
->mnt_opts
!= NULL
)
281 printf (" (%s)", me
->mnt_opts
);
282 if (list_with_volumelabel
&& is_pseudo_fs(me
->mnt_type
) == 0) {
283 const char *devname
= spec_to_devname(me
->mnt_fsname
);
288 label
= fsprobe_get_label_by_devname(devname
);
292 printf (" [%s]", label
);
300 /* Report on everything in mtab (of the specified types if any). */
302 print_all (char *types
) {
303 struct mntentchn
*mc
, *mc0
;
306 for (mc
= mc0
->nxt
; mc
&& mc
!= mc0
; mc
= mc
->nxt
) {
307 if (matching_type (mc
->m
.mnt_type
, types
))
308 print_one (&(mc
->m
));
311 if (!mtab_does_not_exist() && !mtab_is_a_symlink() && is_readonly(_PATH_MOUNTED
))
313 "mount: warning: /etc/mtab is not writable (e.g. read-only filesystem).\n"
314 " It's possible that information reported by mount(8) is not\n"
315 " up to date. For actual information about system mount points\n"
316 " check the /proc/mounts file.\n\n"));
321 /* reallocates its first arg */
323 append_opt(char *s
, const char *opt
, const char *val
)
329 return xstrdup(opt
); /* opt */
331 return xstrconcat3(NULL
, opt
, val
); /* opt=val */
334 return xstrconcat3(s
, ",", opt
); /* s,opt */
336 return xstrconcat4(s
, ",", opt
, val
); /* s,opt=val */
340 append_numopt(char *s
, const char *opt
, unsigned int num
)
344 snprintf(buf
, sizeof(buf
), "%u", num
);
345 return append_opt(s
, opt
, buf
);
348 #ifdef HAVE_LIBSELINUX
349 /* strip quotes from a "string"
350 * Warning: This function modify the "str" argument.
353 strip_quotes(char *str
)
360 end
= strrchr(str
, '"');
361 if (end
== NULL
|| end
== str
)
362 die (EX_USAGE
, _("mount: improperly quoted option string '%s'"), str
);
368 /* translates SELinux context from human to raw format and
369 * appends it to the mount extra options.
371 * returns -1 on error and 0 on success
374 append_context(const char *optname
, char *optdata
, char **extra_opts
)
376 security_context_t raw
= NULL
;
379 if (is_selinux_enabled() != 1)
380 /* ignore the option if we running without selinux */
383 if (optdata
==NULL
|| *optdata
=='\0' || optname
==NULL
)
386 /* TODO: use strip_quotes() for all mount options? */
387 data
= *optdata
=='"' ? strip_quotes(optdata
) : optdata
;
389 if (selinux_trans_to_raw_context(
390 (security_context_t
) data
, &raw
) == -1 ||
395 printf(_("mount: translated %s '%s' to '%s'\n"),
396 optname
, data
, (char *) raw
);
398 *extra_opts
= append_opt(*extra_opts
, optname
, NULL
);
399 *extra_opts
= xstrconcat4(*extra_opts
, "\"", (char *) raw
, "\"");
405 /* returns newly allocated string without *context= options */
406 static char *remove_context_options(char *opts
)
408 char *begin
= NULL
, *end
= NULL
, *p
;
409 int open_quote
= 0, changed
= 0;
414 opts
= xstrdup(opts
);
416 for (p
= opts
; p
&& *p
; p
++) {
418 begin
= p
; /* begin of the option item */
420 open_quote
^= 1; /* reverse the status */
422 continue; /* still in quoted block */
424 end
= p
; /* terminate the option item */
425 else if (*(p
+ 1) == '\0')
426 end
= p
+ 1; /* end of optstr */
430 if (strncmp(begin
, "context=", 8) == 0 ||
431 strncmp(begin
, "fscontext=", 10) == 0 ||
432 strncmp(begin
, "defcontext=", 11) == 0 ||
433 strncmp(begin
, "rootcontext=", 12) == 0) {
436 if ((begin
== opts
|| *(begin
- 1) == ',') && *end
== ',')
440 memmove(begin
, end
, sz
+ 1);
441 if (!*begin
&& *(begin
- 1) == ',')
449 if (changed
&& verbose
)
450 printf (_("mount: SELinux *context= options are ignore on remount.\n"));
457 * Look for OPT in opt_map table and return mask value.
458 * If OPT isn't found, tack it onto extra_opts (which is non-NULL).
459 * For the options uid= and gid= replace user or group name by its value.
462 parse_opt(char *opt
, int *mask
, char **extra_opts
) {
463 const struct opt_map
*om
;
465 for (om
= opt_map
; om
->opt
!= NULL
; om
++)
466 if (streq (opt
, om
->opt
)) {
471 if ((om
->mask
== MS_USER
|| om
->mask
== MS_USERS
)
474 if ((om
->mask
== MS_OWNER
|| om
->mask
== MS_GROUP
)
476 *mask
|= MS_OWNERSECURE
;
478 if (om
->mask
== MS_SILENT
&& om
->inv
) {
483 if (streq(opt
, "nofail"))
488 /* convert nonnumeric ids to numeric */
489 if (!strncmp(opt
, "uid=", 4) && !isdigit(opt
[4])) {
490 struct passwd
*pw
= getpwnam(opt
+4);
493 *extra_opts
= append_numopt(*extra_opts
,
498 if (!strncmp(opt
, "gid=", 4) && !isdigit(opt
[4])) {
499 struct group
*gr
= getgrnam(opt
+4);
502 *extra_opts
= append_numopt(*extra_opts
,
508 #ifdef HAVE_LIBSELINUX
509 if (strncmp(opt
, "context=", 8) == 0 && *(opt
+8)) {
510 if (append_context("context=", opt
+8, extra_opts
) == 0)
513 if (strncmp(opt
, "fscontext=", 10) == 0 && *(opt
+10)) {
514 if (append_context("fscontext=", opt
+10, extra_opts
) == 0)
517 if (strncmp(opt
, "defcontext=", 11) == 0 && *(opt
+11)) {
518 if (append_context("defcontext=", opt
+11, extra_opts
) == 0)
521 if (strncmp(opt
, "rootcontext=", 12) == 0 && *(opt
+12)) {
522 if (append_context("rootcontext=", opt
+12, extra_opts
) == 0)
526 *extra_opts
= append_opt(*extra_opts
, opt
, NULL
);
529 /* Take -o options list and compute 4th and 5th args to mount(2). flags
530 gets the standard options (indicated by bits) and extra_opts all the rest */
532 parse_opts (const char *options
, int *flags
, char **extra_opts
) {
538 if (options
!= NULL
) {
539 char *opts
= xstrdup(options
);
543 for (p
=opts
, opt
=NULL
; p
&& *p
; p
++) {
545 opt
= p
; /* begin of the option item */
547 open_quote
^= 1; /* reverse the status */
549 continue; /* still in quoted block */
551 *p
= '\0'; /* terminate the option item */
552 /* end of option item or last item */
553 if (*p
== '\0' || *(p
+1) == '\0') {
554 if (!parse_string_opt(opt
))
555 parse_opt(opt
, flags
, extra_opts
);
565 *flags
&= ~MS_RDONLY
;
569 /* The propagation flags should not be used together with any other flags */
570 if (*flags
& MS_PROPAGATION
)
571 *flags
&= MS_PROPAGATION
;
574 /* Try to build a canonical options string. */
576 fix_opts_string (int flags
, const char *extra_opts
, const char *user
) {
577 const struct opt_map
*om
;
578 const struct string_opt_map
*m
;
581 new_opts
= append_opt(NULL
, (flags
& MS_RDONLY
) ? "ro" : "rw", NULL
);
582 for (om
= opt_map
; om
->opt
!= NULL
; om
++) {
585 if (om
->inv
|| !om
->mask
|| (flags
& om
->mask
) != om
->mask
)
587 new_opts
= append_opt(new_opts
, om
->opt
, NULL
);
590 for (m
= &string_opt_map
[0]; m
->tag
; m
++) {
591 if (!m
->skip
&& *(m
->valptr
))
592 new_opts
= append_opt(new_opts
, m
->tag
, *(m
->valptr
));
594 if (extra_opts
&& *extra_opts
)
595 new_opts
= append_opt(new_opts
, extra_opts
, NULL
);
598 new_opts
= append_opt(new_opts
, "user=", user
);
604 already (const char *spec0
, const char *node0
) {
605 struct mntentchn
*mc
;
607 char *spec
= canonicalize_spec(spec0
);
608 char *node
= canonicalize(node0
);
610 if ((mc
= getmntfile(node
)) != NULL
)
611 error (_("mount: according to mtab, "
612 "%s is already mounted on %s"),
613 mc
->m
.mnt_fsname
, node
);
614 else if (spec
&& strcmp (spec
, "none") &&
615 (mc
= getmntfile(spec
)) != NULL
)
616 error (_("mount: according to mtab, %s is mounted on %s"),
617 spec
, mc
->m
.mnt_dir
);
627 /* Create mtab with a root entry. */
630 struct mntentchn
*fstab
;
631 struct my_mntent mnt
;
637 mfp
= my_setmntent (_PATH_MOUNTED
, "a+");
638 if (mfp
== NULL
|| mfp
->mntent_fp
== NULL
) {
640 die (EX_FILEIO
, _("mount: can't open %s for writing: %s"),
641 _PATH_MOUNTED
, strerror (errsv
));
644 /* Find the root entry by looking it up in fstab */
645 if ((fstab
= getfs_by_dir ("/")) || (fstab
= getfs_by_dir ("root"))) {
647 parse_opts (fstab
->m
.mnt_opts
, &flags
, &extra_opts
);
649 mnt
.mnt_fsname
= spec_to_devname(fstab
->m
.mnt_fsname
);
650 mnt
.mnt_type
= fstab
->m
.mnt_type
;
651 mnt
.mnt_opts
= fix_opts_string (flags
, extra_opts
, NULL
);
652 mnt
.mnt_freq
= mnt
.mnt_passno
= 0;
655 if (my_addmntent (mfp
, &mnt
) == 1) {
657 die (EX_FILEIO
, _("mount: error writing %s: %s"),
658 _PATH_MOUNTED
, strerror (errsv
));
661 if (fchmod (fileno (mfp
->mntent_fp
), 0644) < 0)
662 if (errno
!= EROFS
) {
665 _("mount: error changing mode of %s: %s"),
666 _PATH_MOUNTED
, strerror (errsv
));
675 /* count successful mount system calls */
676 static int mountcount
= 0;
680 * Mount a single file system. Keep track of successes.
681 * returns: 0: OK, -1: error in errno
684 do_mount_syscall (struct mountargs
*args
) {
685 int flags
= args
->flags
;
687 if ((flags
& MS_MGC_MSK
) == 0)
691 printf("mount: mount(2) syscall: source: \"%s\", target: \"%s\", "
692 "filesystemtype: \"%s\", mountflags: %d, data: %s\n",
693 args
->spec
, args
->node
, args
->type
, flags
, (char *) args
->data
);
695 return mount (args
->spec
, args
->node
, args
->type
, flags
, args
->data
);
700 * Mount a single file system, possibly invoking an external handler to
701 * do so. Keep track of successes.
702 * returns: 0: OK, -1: error in errno
705 do_mount (struct mountargs
*args
, int *special
, int *status
) {
707 if (check_special_mountprog(args
->spec
, args
->node
, args
->type
,
708 args
->flags
, args
->data
, status
)) {
712 #ifdef HAVE_LIBMOUNT_MOUNT
713 prepare_mtab_entry(args
->spec
, args
->node
, args
->type
,
714 mtab_opts
, mtab_flags
);
716 ret
= do_mount_syscall(args
);
724 * check_special_mountprog()
725 * If there is a special mount program for this type, exec it.
726 * returns: 0: no exec was done, 1: exec was done, status has result
729 check_special_mountprog(const char *spec
, const char *node
, const char *type
, int flags
,
730 char *extra_opts
, int *status
) {
731 char search_path
[] = FS_SEARCH_PATH
;
732 char *path
, mountprog
[150];
736 if (!external_allowed
)
739 if (type
== NULL
|| strcmp(type
, "none") == 0)
742 path
= strtok(search_path
, ":");
746 res
= snprintf(mountprog
, sizeof(mountprog
), "%s/mount.%s",
748 path
= strtok(NULL
, ":");
749 if (res
>= sizeof(mountprog
) || res
< 0)
752 res
= stat(mountprog
, &statbuf
);
753 if (res
== -1 && errno
== ENOENT
&& strchr(type
, '.')) {
754 /* If type ends with ".subtype" try without it */
755 *strrchr(mountprog
, '.') = '\0';
757 res
= stat(mountprog
, &statbuf
);
766 case 0: { /* child */
767 char *oo
, *mountargs
[12];
770 if (setgid(getgid()) < 0)
771 die(EX_FAIL
, _("mount: cannot set group id: %s"), strerror(errno
));
773 if (setuid(getuid()) < 0)
774 die(EX_FAIL
, _("mount: cannot set user id: %s"), strerror(errno
));
776 oo
= fix_opts_string (flags
, extra_opts
, NULL
);
777 mountargs
[i
++] = mountprog
; /* 1 */
778 mountargs
[i
++] = (char *) spec
; /* 2 */
779 mountargs
[i
++] = (char *) node
; /* 3 */
780 if (sloppy
&& strncmp(type
, "nfs", 3) == 0)
781 mountargs
[i
++] = "-s"; /* 4 */
783 mountargs
[i
++] = "-f"; /* 5 */
785 mountargs
[i
++] = "-n"; /* 6 */
787 mountargs
[i
++] = "-v"; /* 7 */
789 mountargs
[i
++] = "-o"; /* 8 */
790 mountargs
[i
++] = oo
; /* 9 */
793 mountargs
[i
++] = "-t"; /* 10 */
794 mountargs
[i
++] = (char *) type
; /* 11 */
796 mountargs
[i
] = NULL
; /* 12 */
800 while (mountargs
[i
]) {
801 printf("mount: external mount: argv[%d] = \"%s\"\n",
808 execv(mountprog
, mountargs
);
809 exit(1); /* exec failed */
812 default: { /* parent */
815 *status
= (WIFEXITED(st
) ? WEXITSTATUS(st
) : EX_SYSERR
);
819 case -1: { /* error */
821 error(_("mount: cannot fork: %s"), strerror(errsv
));
830 /* list of already tested filesystems by procfsloop_mount() */
831 static struct tried
{
837 was_tested(const char *fstype
) {
840 for (t
= tried
; t
; t
= t
->next
) {
841 if (!strcmp(t
->type
, fstype
))
848 set_tested(const char *fstype
) {
849 struct tried
*t
= xmalloc(sizeof(struct tried
));
852 t
->type
= xstrdup(fstype
);
858 struct tried
*t
, *tt
;
871 procfsnext(FILE *procfs
) {
875 while (fgets(line
, sizeof(line
), procfs
)) {
876 if (sscanf (line
, "nodev %[^#\n]\n", fsname
) == 1) continue;
877 if (sscanf (line
, " %[^# \n]\n", fsname
) != 1) continue;
878 return xstrdup(fsname
);
883 /* Only use /proc/filesystems here, this is meant to test what
884 the kernel knows about, so /etc/filesystems is irrelevant.
885 Return: 1: yes, 0: no, -1: cannot open procfs */
887 known_fstype_in_procfs(const char *type
)
893 procfs
= fopen(_PATH_PROC_FILESYSTEMS
, "r");
896 while ((fsname
= procfsnext(procfs
)) != NULL
)
897 if (!strcmp(fsname
, type
)) {
907 /* Try all types in FILESYSTEMS, except those in *types,
908 in case *types starts with "no" */
909 /* return: 0: OK, -1: error in errno, 1: type not found */
910 /* when 0 or -1 is returned, *types contains the type used */
911 /* when 1 is returned, *types is NULL */
913 procfsloop_mount(int (*mount_fn
)(struct mountargs
*, int *, int *),
914 struct mountargs
*args
,
916 int *special
, int *status
)
918 char *files
[2] = { _PATH_FILESYSTEMS
, _PATH_PROC_FILESYSTEMS
};
921 const char *notypes
= NULL
;
927 if (*types
&& !strncmp(*types
, "no", 2)) {
929 notypes
= (*types
) + 2;
933 /* Use _PATH_PROC_FILESYSTEMS only when _PATH_FILESYSTEMS
934 * (/etc/filesystems) does not exist. In some cases trying a
935 * filesystem that the kernel knows about on the wrong data will crash
936 * the kernel; in such cases _PATH_FILESYSTEMS can be used to list the
937 * filesystems that we are allowed to try, and in the order they should
938 * be tried. End _PATH_FILESYSTEMS with a line containing a single '*'
939 * only, if _PATH_PROC_FILESYSTEMS should be tried afterwards.
941 for (i
=0; i
<2; i
++) {
942 procfs
= fopen(files
[i
], "r");
945 while ((fsname
= procfsnext(procfs
)) != NULL
) {
946 if (!strcmp(fsname
, "*")) {
950 if (was_tested (fsname
))
952 if (no
&& matching_type(fsname
, notypes
))
957 printf(_("Trying %s\n"), fsname
);
958 if ((*mount_fn
) (args
, special
, status
) == 0) {
962 } else if (errno
!= EINVAL
&&
963 known_fstype_in_procfs(fsname
) == 1) {
980 guess_fstype_by_devname(const char *devname
, int *ambivalent
)
982 const char *type
= fsprobe_get_fstype_by_devname_ambi(devname
, ambivalent
);
985 printf (_("mount: you didn't specify a filesystem type for %s\n"), devname
);
988 printf (_(" I will try all types mentioned in %s or %s\n"),
989 _PATH_FILESYSTEMS
, _PATH_PROC_FILESYSTEMS
);
990 else if (!strcmp(type
, MNTTYPE_SWAP
))
991 printf (_(" and it looks like this is swapspace\n"));
993 printf (_(" I will try type %s\n"), type
);
999 * guess_fstype_and_mount()
1000 * Mount a single file system. Guess the type when unknown.
1001 * returns: 0: OK, -1: error in errno, 1: other error
1002 * don't exit on non-fatal errors.
1003 * on return types is filled with the type used.
1006 guess_fstype_and_mount(const char *spec
, const char *node
, const char **types
,
1007 int flags
, char *mount_opts
, int *special
, int *status
) {
1008 struct mountargs args
= { spec
, node
, NULL
, flags
& ~MS_NOSYS
, mount_opts
};
1011 if (*types
&& strcasecmp (*types
, "auto") == 0)
1014 if (!*types
&& !(flags
& MS_REMOUNT
)) {
1015 *types
= guess_fstype_by_devname(spec
, &ambivalent
);
1017 if (!strcmp(*types
, MNTTYPE_SWAP
)) {
1018 error(_("%s looks like swapspace - not mounted"), spec
);
1023 return do_mount (&args
, special
, status
);
1025 } else if (ambivalent
) {
1026 error(_("mount: %s: more filesystems detected. This should not happen,\n"
1027 " use -t <type> to explicitly specify the filesystem type or\n"
1028 " use wipefs(8) to clean up the device.\n"), spec
);
1033 /* Accept a comma-separated list of types, and try them one by one */
1034 /* A list like "nonfs,.." indicates types not to use */
1035 if (*types
&& strncmp(*types
, "no", 2) && strchr(*types
,',')) {
1036 char *t
= strdup(*types
);
1039 while((p
= strchr(t
,',')) != NULL
) {
1041 args
.type
= *types
= t
;
1042 if (do_mount (&args
, special
, status
) == 0)
1046 /* do last type below */
1050 if (*types
|| (flags
& MS_REMOUNT
)) {
1052 return do_mount (&args
, special
, status
);
1055 return procfsloop_mount(do_mount
, &args
, types
, special
, status
);
1059 * restricted_check()
1060 * Die if the user is not allowed to do this.
1063 restricted_check(const char *spec
, const char *node
, int *flags
, char **user
) {
1066 * MS_OWNER: Allow owners to mount when fstab contains
1067 * the owner option. Note that this should never be used
1068 * in a high security environment, but may be useful to give
1069 * people at the console the possibility of mounting a floppy.
1070 * MS_GROUP: Allow members of device group to mount. (Martin Dickopp)
1072 if (*flags
& (MS_OWNER
| MS_GROUP
)) {
1075 if (!strncmp(spec
, "/dev/", 5) && stat(spec
, &sb
) == 0) {
1077 if (*flags
& MS_OWNER
) {
1078 if (getuid() == sb
.st_uid
)
1082 if (*flags
& MS_GROUP
) {
1083 if (getgid() == sb
.st_gid
)
1086 int n
= getgroups(0, NULL
);
1089 gid_t
*groups
= xmalloc(n
* sizeof(*groups
));
1090 if (getgroups(n
, groups
) == n
) {
1092 for (i
= 0; i
< n
; i
++) {
1093 if (groups
[i
] == sb
.st_gid
) {
1106 /* James Kehl <mkehl@gil.com.au> came with a similar patch:
1107 allow an arbitrary user to mount when he is the owner of
1108 the mount-point and has write-access to the device.
1109 This is even less secure. Let me skip it for the time being;
1110 there should be an explicit fstab line allowing such things. */
1112 if (!(*flags
& (MS_USER
| MS_USERS
))) {
1113 if (already (spec
, node
))
1114 die (EX_USAGE
, _("mount failed"));
1116 die (EX_USAGE
, _("mount: only root can mount %s on %s"), spec
, node
);
1118 if (*flags
& MS_USER
)
1119 *user
= getusername();
1122 *flags
&= ~(MS_OWNER
| MS_GROUP
);
1125 /* Check, if there already exists a mounted loop device on the mountpoint node
1126 * with the same parameters.
1129 is_mounted_same_loopfile(const char *node0
, const char *loopfile
, unsigned long long offset
)
1131 struct mntentchn
*mnt
= NULL
;
1135 node
= canonicalize(node0
);
1137 /* Search for mountpoint node in mtab,
1138 * procceed if any of these has the loop option set or
1139 * the device is a loop device
1141 mnt
= getmntdirbackward(node
, mnt
);
1146 for(; mnt
&& res
== 0; mnt
= getmntdirbackward(node
, mnt
)) {
1149 if (strncmp(mnt
->m
.mnt_fsname
, "/dev/loop", 9) == 0)
1150 res
= loopfile_used_with((char *) mnt
->m
.mnt_fsname
,
1153 else if ((p
= strstr(mnt
->m
.mnt_opts
, "loop="))) {
1154 char *dev
= xstrdup(p
+5);
1155 if ((p
= strchr(dev
, ',')))
1157 res
= loopfile_used_with(dev
, loopfile
, offset
);
1167 parse_offset(const char **opt
, uintmax_t *val
)
1171 if (strtosize(*opt
, val
))
1175 snprintf(tmp
, 32, "%jd", *val
);
1182 loop_check(const char **spec
, const char **type
, int *flags
,
1183 int *loop
, const char **loopdev
, const char **loopfile
,
1186 uintmax_t offset
= 0, sizelimit
= 0;
1189 * In the case of a loop mount, either type is of the form lo@/dev/loop5
1190 * or the option "-o loop=/dev/loop5" or just "-o loop" is given, or
1191 * mount just has to figure things out for itself from the fact that
1192 * spec is not a block device. We do not test for a block device
1193 * immediately: maybe later other types of mountable objects will occur.
1196 *loopdev
= opt_loopdev
;
1198 looptype
= (*type
&& strncmp("lo@", *type
, 3) == 0);
1201 error(_("mount: loop device specified twice"));
1202 *loopdev
= *type
+ 3;
1203 *type
= opt_vfstype
;
1204 } else if (opt_vfstype
) {
1206 error(_("mount: type specified twice"));
1208 *type
= opt_vfstype
;
1211 *loop
= ((*flags
& MS_LOOP
) || *loopdev
|| opt_offset
|| opt_sizelimit
|| opt_encryption
);
1214 /* Automatically create a loop device from a regular file if a filesystem
1215 * is not specified or the filesystem is known for libblkid (these
1216 * filesystems work with block devices only).
1218 * Note that there is not a restriction (on kernel side) that prevents regular
1219 * file as a mount(2) source argument. A filesystem that is able to mount
1220 * regular files could be implemented.
1222 if (!*loop
&& !(*flags
& (MS_BIND
| MS_MOVE
| MS_PROPAGATION
)) &&
1223 (!*type
|| strcmp(*type
, "auto") == 0 || fsprobe_known_fstype(*type
))) {
1226 if (stat(*loopfile
, &st
) == 0)
1227 *loop
= S_ISREG(st
.st_mode
);
1234 printf(_("mount: skipping the setup of a loop device\n"));
1239 /* since 2.6.37 we don't have to store backing filename to mtab
1240 * because kernel provides the name in /sys
1242 if (get_linux_version() >= KERNEL_VERSION(2, 6, 37) ||
1243 mtab_is_writable() == 0) {
1246 printf(_("mount: enabling autoclear loopdev flag\n"));
1247 loop_opts
= SETLOOP_AUTOCLEAR
;
1250 if (*flags
& MS_RDONLY
)
1251 loop_opts
|= SETLOOP_RDONLY
;
1253 if (opt_offset
&& parse_offset(&opt_offset
, &offset
)) {
1254 error(_("mount: invalid offset '%s' specified"), opt_offset
);
1257 if (opt_sizelimit
&& parse_offset(&opt_sizelimit
, &sizelimit
)) {
1258 error(_("mount: invalid sizelimit '%s' specified"), opt_sizelimit
);
1262 if (is_mounted_same_loopfile(node
, *loopfile
, offset
)) {
1263 error(_("mount: according to mtab %s is already mounted on %s as loop"), *loopfile
, node
);
1268 if (!*loopdev
|| !**loopdev
)
1269 *loopdev
= find_unused_loop_device();
1271 return EX_SYSERR
; /* no more loop devices */
1273 printf(_("mount: going to use the loop device %s\n"), *loopdev
);
1275 if ((res
= set_loop(*loopdev
, *loopfile
, offset
, sizelimit
,
1276 opt_encryption
, pfd
, &loop_opts
))) {
1278 /* loop dev has been grabbed by some other process,
1279 try again, if not given explicitly */
1282 printf(_("mount: stolen loop=%s ...trying again\n"), *loopdev
);
1287 error(_("mount: stolen loop=%s"), *loopdev
);
1292 printf(_("mount: failed setting up loop device\n"));
1300 } while (!*loopdev
);
1303 printf(_("mount: setup loop device successfully\n"));
1306 if (loop_opts
& SETLOOP_RDONLY
)
1307 *flags
|= MS_RDONLY
;
1309 if (loop_opts
& SETLOOP_AUTOCLEAR
)
1310 /* Prevent recording loop dev in mtab for cleanup on umount */
1319 #ifdef HAVE_LIBMOUNT_MOUNT
1321 verbose_mount_info(const char *spec
, const char *node
, const char *type
,
1322 const char *opts
, int flags
)
1324 struct my_mntent mnt
;
1326 mnt
.mnt_fsname
= is_pseudo_fs(type
) ? spec
: canonicalize(spec
);
1327 mnt
.mnt_dir
= canonicalize (node
);
1328 mnt
.mnt_type
= type
;
1329 mnt
.mnt_opts
= opts
;
1333 if (spec
!= mnt
.mnt_fsname
)
1334 my_free(mnt
.mnt_fsname
);
1335 my_free(mnt
.mnt_dir
);
1339 prepare_mtab_entry(const char *spec
, const char *node
, const char *type
,
1340 const char *opts
, unsigned long flags
)
1342 struct libmnt_fs
*fs
= mnt_new_fs();
1346 mtab_update
= mnt_new_update();
1348 if (mtab_update
&& fs
) {
1349 const char *cn_spec
= is_pseudo_fs(type
) ? spec
: canonicalize(spec
);
1350 const char *cn_node
= canonicalize(node
);
1352 mnt_fs_set_source(fs
, cn_spec
);
1353 mnt_fs_set_target(fs
, cn_node
);
1354 mnt_fs_set_fstype(fs
, type
);
1355 mnt_fs_set_options(fs
, opts
);
1357 rc
= mnt_update_set_fs(mtab_update
, flags
, NULL
, fs
);
1359 if (spec
!= cn_spec
)
1367 mnt_free_update(mtab_update
);
1372 static void update_mtab_entry(int flags
)
1375 struct libmnt_lock
*lc
;
1380 fl
= mnt_update_get_mflags(mtab_update
);
1382 if ((flags
& MS_RDONLY
) != (fl
& MS_RDONLY
))
1383 mnt_update_force_rdonly(mtab_update
, flags
& MS_RDONLY
);
1386 if (mtab_does_not_exist()) {
1388 printf(_("mount: no %s found - creating it..\n"),
1393 lc
= init_libmount_lock( mnt_update_get_filename(mtab_update
) );
1394 mnt_update_table(mtab_update
, lc
);
1395 init_libmount_lock(NULL
);
1398 mnt_free_update(mtab_update
);
1402 #else /*!HAVE_LIBMOUNT_MOUNT */
1404 update_mtab_entry(const char *spec
, const char *node
, const char *type
,
1405 const char *opts
, int flags
, int freq
, int pass
) {
1406 struct my_mntent mnt
;
1408 mnt
.mnt_fsname
= is_pseudo_fs(type
) ? xstrdup(spec
) : canonicalize(spec
);
1409 mnt
.mnt_dir
= canonicalize (node
);
1410 mnt
.mnt_type
= type
;
1411 mnt
.mnt_opts
= opts
;
1412 mnt
.mnt_freq
= freq
;
1413 mnt
.mnt_passno
= pass
;
1415 /* We get chatty now rather than after the update to mtab since the
1416 mount succeeded, even if the write to /etc/mtab should fail. */
1420 if (!nomtab
&& mtab_does_not_exist()) {
1422 printf(_("mount: no %s found - creating it..\n"),
1428 if (!nomtab
&& mtab_is_writable()) {
1429 if (flags
& MS_REMOUNT
)
1430 update_mtab (mnt
.mnt_dir
, &mnt
);
1431 else if (flags
& MS_MOVE
)
1432 update_mtab(mnt
.mnt_fsname
, &mnt
);
1437 mfp
= my_setmntent(_PATH_MOUNTED
, "a+");
1438 if (mfp
== NULL
|| mfp
->mntent_fp
== NULL
) {
1440 error(_("mount: can't open %s: %s"), _PATH_MOUNTED
,
1443 if ((my_addmntent (mfp
, &mnt
)) == 1) {
1445 error(_("mount: error writing %s: %s"),
1446 _PATH_MOUNTED
, strerror (errsv
));
1453 my_free(mnt
.mnt_fsname
);
1454 my_free(mnt
.mnt_dir
);
1456 #endif /* !HAVE_LIBMOUNT_MOUNT */
1462 _("mount: argument to -p or --pass-fd must be a number"));
1467 cdrom_setspeed(const char *spec
) {
1468 #define CDROM_SELECT_SPEED 0x5322 /* Set the CD-ROM speed */
1471 int speed
= atoi(opt_speed
);
1473 if ((cdrom
= open(spec
, O_RDONLY
| O_NONBLOCK
)) < 0)
1475 _("mount: cannot open %s for setting speed"),
1477 if (ioctl(cdrom
, CDROM_SELECT_SPEED
, speed
) < 0)
1478 die(EX_FAIL
, _("mount: cannot set speed: %s"),
1485 * Check if @path is on read-only filesystem independently on file permissions.
1488 is_readonly(const char *path
)
1490 if (access(path
, W_OK
) == 0)
1494 if (errno
!= EACCES
)
1497 #ifdef HAVE_FUTIMENS
1499 * access(2) returns EACCES on read-only FS:
1501 * - for set-uid application if one component of the path is not
1502 * accessible for the current rUID. (Note that euidaccess(2) does not
1503 * check for EROFS at all).
1505 * - for read-write filesystem with read-only VFS node (aka -o remount,ro,bind)
1508 struct timespec times
[2];
1510 times
[0].tv_nsec
= UTIME_NOW
; /* atime */
1511 times
[1].tv_nsec
= UTIME_OMIT
; /* mtime */
1513 if (utimensat(AT_FDCWD
, path
, times
, 0) == -1)
1514 return errno
== EROFS
;
1522 * Try to mount one file system.
1524 * returns: 0: OK, EX_SYSERR, EX_FAIL, return code from nfsmount,
1525 * return status from wait
1528 try_mount_one (const char *spec0
, const char *node0
, const char *types0
,
1529 const char *opts0
, int freq
, int pass
, int ro
) {
1530 int res
= 0, status
= 0, special
= 0;
1531 int mnt5_res
= 0; /* only for gcc */
1534 char *extra_opts
; /* written in mtab */
1535 char *mount_opts
; /* actually used on system call */
1536 const char *opts
, *spec
, *node
, *types
;
1539 const char *loopdev
= 0, *loopfile
= 0;
1540 struct stat statbuf
;
1542 /* copies for freeing on exit */
1543 const char *opts1
, *spec1
, *node1
, *types1
, *extra_opts1
;
1546 printf("mount: spec: \"%s\"\n", spec0
);
1547 printf("mount: node: \"%s\"\n", node0
);
1548 printf("mount: types: \"%s\"\n", types0
);
1549 printf("mount: opts: \"%s\"\n", opts0
);
1552 spec
= spec1
= xstrdup(spec0
);
1553 node
= node1
= xstrdup(node0
);
1554 types
= types1
= xstrdup(types0
);
1555 opts
= opts1
= xstrdup(opts0
);
1557 parse_opts (opts
, &flags
, &extra_opts
);
1558 extra_opts1
= extra_opts
;
1559 mount_opts
= extra_opts
;
1561 /* quietly succeed for fstab entries that don't get mounted automatically */
1562 if (mount_all
&& (flags
& MS_NOAUTO
))
1565 restricted_check(spec
, node
, &flags
, &user
);
1567 /* The "mount -f" checks for for existing record in /etc/mtab (with
1568 * regular non-fake mount this is usually done by kernel)
1570 if (!(flags
& MS_REMOUNT
) && fake
&& mounted (spec
, node
))
1571 die(EX_USAGE
, _("mount: according to mtab, "
1572 "%s is already mounted on %s\n"),
1576 cdrom_setspeed(spec
);
1578 if (!(flags
& MS_REMOUNT
)) {
1580 * Don't set up a (new) loop device if we only remount - this left
1581 * stale assignments of files to loop devices. Nasty when used for
1584 res
= loop_check(&spec
, &types
, &flags
, &loop
, &loopdev
, &loopfile
, node
);
1590 opt_loopdev
= loopdev
;
1592 if (flags
& (MS_BIND
| MS_MOVE
| MS_PROPAGATION
))
1595 #ifdef HAVE_LIBSELINUX
1596 if ((flags
& MS_REMOUNT
) && mount_opts
)
1597 mount_opts
= remove_context_options(mount_opts
);
1601 * Call mount.TYPE for types that require a separate mount program.
1602 * For the moment these types are ncpfs and smbfs. Maybe also vxfs.
1603 * All such special things must occur isolated in the types string.
1605 if (check_special_mountprog(spec
, node
, types
, flags
, mount_opts
, &status
)) {
1610 #ifdef HAVE_LIBMOUNT_MOUNT
1611 mtab_opts
= fix_opts_string(flags
& ~MS_NOMTAB
, extra_opts
, user
);
1615 block_signals (SIG_BLOCK
);
1618 mnt5_res
= guess_fstype_and_mount (spec
, node
, &types
, flags
& ~MS_NOSYS
,
1619 mount_opts
, &special
, &status
);
1622 block_signals (SIG_UNBLOCK
);
1628 /* Kernel allows to use MS_RDONLY for bind mounts, but the read-only request
1629 * could be silently ignored. Check it to avoid 'ro' in mtab and 'rw' in
1632 if (!fake
&& mnt5_res
== 0 &&
1633 (flags
& MS_BIND
) && (flags
& MS_RDONLY
) && !is_readonly(node
)) {
1635 printf(_("mount: warning: %s seems to be mounted read-write.\n"), node
);
1636 flags
&= ~MS_RDONLY
;
1639 /* Kernel can silently add MS_RDONLY flag when mounting file system that
1640 * does not have write support. Check this to avoid 'ro' in /proc/mounts
1643 if (!fake
&& mnt5_res
== 0 &&
1644 !(flags
& (MS_RDONLY
| MS_PROPAGATION
| MS_MOVE
)) &&
1645 is_readonly(node
)) {
1647 printf(_("mount: warning: %s seems to be mounted read-only.\n"), node
);
1651 if (fake
|| mnt5_res
== 0) {
1652 char *mo
= fix_opts_string (flags
& ~MS_NOMTAB
, extra_opts
, user
);
1653 const char *tp
= types
? types
: "unknown";
1655 /* Mount succeeded, report this (if verbose) and write mtab entry. */
1656 #ifdef HAVE_LIBMOUNT_MOUNT
1657 update_mtab_entry(flags
);
1659 verbose_mount_info(loop
? loopfile
: spec
, node
, tp
, mo
, flags
);
1661 if (!(mounttype
& MS_PROPAGATION
))
1662 update_mtab_entry(loop
? loopfile
: spec
,
1670 block_signals (SIG_UNBLOCK
);
1682 block_signals (SIG_UNBLOCK
);
1684 /* Mount failed, complain, but don't die. */
1688 error (_("mount: I could not determine the filesystem type, "
1689 "and none was specified"));
1691 error (_("mount: you must specify the filesystem type"));
1692 } else if (mnt5_res
!= -1) {
1693 /* should not happen */
1694 error (_("mount: mount failed"));
1698 if (geteuid() == 0) {
1699 if (stat (node
, &statbuf
) || !S_ISDIR(statbuf
.st_mode
))
1700 error (_("mount: mount point %s is not a directory"), node
);
1702 error (_("mount: permission denied"));
1704 error (_("mount: must be superuser to use mount"));
1707 if (flags
& MS_REMOUNT
) {
1708 error (_("mount: %s is busy"), node
);
1709 } else if (!strcmp(types
, "proc") && !strcmp(node
, "/proc")) {
1710 /* heuristic: if /proc/version exists, then probably proc is mounted */
1711 if (stat ("/proc/version", &statbuf
)) /* proc mounted? */
1712 error (_("mount: %s is busy"), node
); /* no */
1713 else if (!mount_all
|| verbose
) /* yes, don't mention it */
1714 error (_("mount: proc already mounted"));
1716 error (_("mount: %s already mounted or %s busy"), spec
, node
);
1717 already (spec
, node
);
1721 if (lstat (node
, &statbuf
))
1722 error (_("mount: mount point %s does not exist"), node
);
1723 else if (stat (node
, &statbuf
))
1724 error (_("mount: mount point %s is a symbolic link to nowhere"),
1726 else if (stat (spec
, &statbuf
)) {
1729 error (_("mount: special device %s does not exist"), spec
);
1736 if (stat (node
, &statbuf
) || ! S_ISDIR(statbuf
.st_mode
))
1737 error (_("mount: mount point %s is not a directory"), node
);
1738 else if (stat (spec
, &statbuf
) && errno
== ENOTDIR
) {
1741 error (_("mount: special device %s does not exist\n"
1742 " (a path prefix is not a directory)\n"), spec
);
1750 unsigned long long size
= 0;
1752 if (flags
& MS_REMOUNT
) {
1753 error (_("mount: %s not mounted already, or bad option"), node
);
1755 error (_("mount: wrong fs type, bad option, bad superblock on %s,\n"
1756 " missing codepage or helper program, or other error"),
1759 if (stat(spec
, &statbuf
) < 0) {
1760 if (errno
== ENOENT
) /* network FS? */
1762 " (for several filesystems (e.g. nfs, cifs) you might\n"
1763 " need a /sbin/mount.<type> helper program)"));
1765 } else if (S_ISBLK(statbuf
.st_mode
)
1766 && (fd
= open(spec
, O_RDONLY
| O_NONBLOCK
)) >= 0) {
1768 if (blkdev_get_size(fd
, &size
) == 0) {
1769 if (size
== 0 && !loop
)
1771 " (could this be the IDE device where you in fact use\n"
1772 " ide-scsi so that sr0 or sda or so is needed?)"));
1774 if (size
&& size
<= 2)
1776 " (aren't you trying to mount an extended partition,\n"
1777 " instead of some logical partition inside?)"));
1783 " In some cases useful info is found in syslog - try\n"
1784 " dmesg | tail or so\n"));
1789 error (_("mount table full")); break;
1791 error (_("mount: %s: can't read superblock"), spec
); break;
1794 int pfs
= known_fstype_in_procfs(types
);
1796 if (pfs
== 1 || !strcmp(types
, "guess"))
1797 error(_("mount: %s: unknown device"), spec
);
1798 else if (pfs
== 0) {
1802 error (_("mount: unknown filesystem type '%s'"), types
);
1804 /* maybe this loser asked for FAT or ISO9660 or isofs */
1805 lowtype
= xstrdup(types
);
1807 for(p
=lowtype
; *p
; p
++) {
1808 if(tolower(*p
) != *p
) {
1813 if (u
&& known_fstype_in_procfs(lowtype
) == 1)
1814 error (_("mount: probably you meant %s"), lowtype
);
1815 else if (!strncmp(lowtype
, "iso", 3) &&
1816 known_fstype_in_procfs("iso9660") == 1)
1817 error (_("mount: maybe you meant 'iso9660'?"));
1818 else if (!strncmp(lowtype
, "fat", 3) &&
1819 known_fstype_in_procfs("vfat") == 1)
1820 error (_("mount: maybe you meant 'vfat'?"));
1823 error (_("mount: %s has wrong device number or fs type %s not supported"),
1830 if (stat (spec
, &statbuf
)) /* strange ... */
1831 error (_("mount: %s is not a block device, and stat fails?"), spec
);
1832 else if (S_ISBLK(statbuf
.st_mode
))
1833 error (_("mount: the kernel does not recognize %s as a block device\n"
1834 " (maybe `modprobe driver'?)"), spec
);
1835 else if (S_ISREG(statbuf
.st_mode
))
1836 error (_("mount: %s is not a block device (maybe try `-o loop'?)"),
1839 error (_("mount: %s is not a block device"), spec
);
1844 error (_("mount: %s is not a valid block device"), spec
); break;
1845 case EACCES
: /* pre-linux 1.1.38, 1.1.41 and later */
1846 case EROFS
: /* linux 1.1.38 and later */
1847 { char *bd
= (loop
? "" : _("block device "));
1848 if (ro
|| (flags
& MS_RDONLY
)) {
1849 error (_("mount: cannot mount %s%s read-only"),
1852 } else if (readwrite
) {
1853 error (_("mount: %s%s is write-protected but explicit `-w' flag given"),
1856 } else if (flags
& MS_REMOUNT
) {
1857 error (_("mount: cannot remount %s%s read-write, is write-protected"),
1865 char *opts2
= append_opt(xstrdup(opts
), "ro", NULL
);
1867 opts
= opts1
= opts2
;
1870 if (types
&& !strcmp(types
, "guess"))
1872 error (_("mount: %s%s is write-protected, mounting read-only"),
1874 res
= try_mount_one (spec0
, node0
, types
, opts
, freq
, pass
, 1);
1880 error(_("mount: no medium found on %s"), spec
);
1883 error ("mount: %s", strerror (mnt_err
)); break;
1890 #if defined(HAVE_LIBSELINUX) && defined(HAVE_SECURITY_GET_INITIAL_CONTEXT)
1891 if (res
!= EX_FAIL
&& verbose
&& is_selinux_enabled() > 0) {
1892 security_context_t raw
= NULL
, def
= NULL
;
1894 if (getfilecon(node
, &raw
) > 0 &&
1895 security_get_initial_context("file", &def
) == 0) {
1897 if (!selinux_file_context_cmp(raw
, def
))
1898 printf(_("mount: %s does not contain SELinux labels.\n"
1899 " You just mounted an file system that supports labels which does not\n"
1900 " contain labels, onto an SELinux box. It is likely that confined\n"
1901 " applications will generate AVC messages and not be allowed access to\n"
1902 " this file system. For more details see restorecon(8) and mount(8).\n"),
1910 if (extra_opts1
!= mount_opts
)
1911 my_free(mount_opts
);
1912 my_free(extra_opts1
);
1922 subst_string(const char *s
, const char *sub
, int sublen
, const char *repl
) {
1925 n
= (char *) xmalloc(strlen(s
)-sublen
+strlen(repl
)+1);
1926 strncpy (n
, s
, sub
-s
);
1927 strcpy (n
+ (sub
-s
), repl
);
1928 strcat (n
, sub
+sublen
);
1933 usersubst(const char *opts
) {
1941 if (opts
&& (w
= strstr(opts
, s
)) != NULL
) {
1942 sprintf(id
, "uid=%u", getuid());
1943 opts
= subst_string(opts
, w
, strlen(s
), id
);
1946 if (opts
&& (w
= strstr(opts
, s
)) != NULL
) {
1947 sprintf(id
, "gid=%u", getgid());
1948 opts
= subst_string(opts
, w
, strlen(s
), id
);
1950 return xstrdup(opts
);
1954 is_existing_file (const char *s
) {
1955 struct stat statbuf
;
1957 return (stat(s
, &statbuf
) == 0);
1961 * Return 0 for success (either mounted sth or -a and NOAUTO was given)
1964 mount_one (const char *spec
, const char *node
, const char *types
,
1965 const char *fstabopts
, char *cmdlineopts
, int freq
, int pass
) {
1969 /* Substitute values in opts, if required */
1970 opts
= usersubst(fstabopts
);
1972 /* Merge the fstab and command line options. */
1973 opts
= append_opt(opts
, cmdlineopts
, NULL
);
1975 if (types
== NULL
&& !mounttype
&& !is_existing_file(spec
)) {
1976 if (strchr (spec
, ':') != NULL
) {
1979 printf(_("mount: no type was given - "
1980 "I'll assume nfs because of "
1982 } else if(!strncmp(spec
, "//", 2)) {
1985 printf(_("mount: no type was given - "
1986 "I'll assume cifs because of "
1987 "the // prefix\n"));
1991 /* Handle possible LABEL= and UUID= forms of spec */
1992 if (types
== NULL
|| (strncmp(types
, "9p", 2) &&
1993 strncmp(types
, "nfs", 3) &&
1994 strncmp(types
, "cifs", 4) &&
1995 strncmp(types
, "smbfs", 5))) {
1996 nspec
= spec_to_devname(spec
);
2001 return try_mount_one (spec
, node
, types
, opts
, freq
, pass
, 0);
2004 /* Check if an fsname/dir pair was already in the old mtab. */
2006 mounted (const char *spec0
, const char *node0
) {
2007 struct mntentchn
*mc
, *mc0
;
2008 const char *spec
, *node
;
2011 /* Handle possible UUID= and LABEL= in spec */
2012 spec
= spec_to_devname(spec0
);
2016 node
= canonicalize(node0
);
2019 for (mc
= mc0
->nxt
; mc
&& mc
!= mc0
; mc
= mc
->nxt
)
2020 if (streq (spec
, mc
->m
.mnt_fsname
) &&
2021 streq (node
, mc
->m
.mnt_dir
)) {
2032 /* returns 0 if not mounted, 1 if mounted and -1 in case of error */
2034 is_fstab_entry_mounted(struct mntentchn
*mc
, int verbose
)
2038 if (mounted(mc
->m
.mnt_fsname
, mc
->m
.mnt_dir
))
2041 /* extra care for loop devices */
2042 if ((strstr(mc
->m
.mnt_opts
, "loop=") ||
2043 (stat(mc
->m
.mnt_fsname
, &st
) == 0 && S_ISREG(st
.st_mode
)))) {
2045 char *p
= strstr(mc
->m
.mnt_opts
, "offset=");
2046 uintmax_t offset
= 0;
2048 if (p
&& strtosize(p
+ 7, &offset
) != 0) {
2050 printf(_("mount: ignore %s "
2051 "(unparsable offset= option)\n"),
2055 if (is_mounted_same_loopfile(mc
->m
.mnt_dir
, mc
->m
.mnt_fsname
, offset
))
2062 printf(_("mount: %s already mounted on %s\n"),
2063 mc
->m
.mnt_fsname
, mc
->m
.mnt_dir
);
2067 /* avoid using stat() on things we are not going to mount anyway.. */
2069 has_noauto (const char *opts
) {
2074 s
= strstr(opts
, "noauto");
2077 return (s
== opts
|| s
[-1] == ',') && (s
[6] == 0 || s
[6] == ',');
2080 /* Mount all filesystems of the specified types except swap and root. */
2081 /* With the --fork option: fork and let different incarnations of
2082 mount handle different filesystems. However, try to avoid several
2083 simultaneous mounts on the same physical disk, since that is very slow. */
2084 #define DISKMAJOR(m) (((int) m) & ~0xf)
2087 do_mount_all (char *types
, char *options
, char *test_opts
) {
2088 struct mntentchn
*mc
, *mc0
, *mtmp
;
2090 struct stat statbuf
;
2094 struct mntentchn
*mec
;
2095 struct mntentchn
*meclast
;
2097 } childhead
, *childtail
, *cp
;
2101 /* build a chain of what we have to do, or maybe
2102 several chains, one for each major or NFS host */
2104 childtail
= &childhead
;
2106 for (mc
= mc0
->nxt
; mc
&& mc
!= mc0
; mc
= mc
->nxt
) {
2107 if (has_noauto (mc
->m
.mnt_opts
))
2109 if (matching_type (mc
->m
.mnt_type
, types
)
2110 && matching_opts (mc
->m
.mnt_opts
, test_opts
)
2111 && !streq (mc
->m
.mnt_dir
, "/")
2112 && !streq (mc
->m
.mnt_dir
, "root")
2113 && !is_fstab_entry_mounted(mc
, verbose
)) {
2115 mtmp
= (struct mntentchn
*) xmalloc(sizeof(*mtmp
));
2120 if (stat(mc
->m
.mnt_fsname
, &statbuf
) == 0 &&
2121 S_ISBLK(statbuf
.st_mode
)) {
2122 sprintf(major
, "#%x",
2123 DISKMAJOR(statbuf
.st_rdev
));
2126 if (strcmp(mc
->m
.mnt_type
, "nfs") == 0) {
2127 g
= xstrdup(mc
->m
.mnt_fsname
);
2128 colon
= strchr(g
, ':');
2134 for (cp
= childhead
.nxt
; cp
; cp
= cp
->nxt
)
2136 strcmp(cp
->group
, g
) == 0) {
2137 cp
->meclast
->nxt
= mtmp
;
2142 cp
= (struct child
*) xmalloc(sizeof *cp
);
2144 cp
->mec
= cp
->meclast
= mtmp
;
2145 cp
->group
= xstrdup(g
);
2147 childtail
->nxt
= cp
;
2154 /* now do everything */
2155 for (cp
= childhead
.nxt
; cp
; cp
= cp
->nxt
) {
2161 error(_("mount: cannot fork: %s"),
2168 /* if child, or not forked, do the mounting */
2169 if (p
== 0 || p
== -1) {
2170 for (mc
= cp
->mec
; mc
; mc
= mc
->nxt
) {
2171 status
|= mount_one (mc
->m
.mnt_fsname
,
2178 status
|= EX_SOMEOK
;
2184 /* wait for children, if any */
2185 while ((cp
= childhead
.nxt
) != NULL
) {
2186 childhead
.nxt
= cp
->nxt
;
2190 if(waitpid(cp
->pid
, &ret
, 0) == -1) {
2194 } else if (WIFEXITED(ret
))
2195 status
|= WEXITSTATUS(ret
);
2197 status
|= EX_SYSERR
;
2201 status
|= EX_SOMEOK
;
2205 static struct option longopts
[] = {
2206 { "all", 0, 0, 'a' },
2207 { "fake", 0, 0, 'f' },
2208 { "fork", 0, 0, 'F' },
2209 { "help", 0, 0, 'h' },
2210 { "no-mtab", 0, 0, 'n' },
2211 { "read-only", 0, 0, 'r' },
2212 { "ro", 0, 0, 'r' },
2213 { "verbose", 0, 0, 'v' },
2214 { "version", 0, 0, 'V' },
2215 { "read-write", 0, 0, 'w' },
2216 { "rw", 0, 0, 'w' },
2217 { "options", 1, 0, 'o' },
2218 { "test-opts", 1, 0, 'O' },
2219 { "pass-fd", 1, 0, 'p' },
2220 { "types", 1, 0, 't' },
2221 { "bind", 0, 0, 'B' },
2222 { "move", 0, 0, 'M' },
2223 { "guess-fstype", 1, 0, 134 },
2224 { "rbind", 0, 0, 'R' },
2225 { "make-shared", 0, 0, 136 },
2226 { "make-slave", 0, 0, 137 },
2227 { "make-private", 0, 0, 138 },
2228 { "make-unbindable", 0, 0, 139 },
2229 { "make-rshared", 0, 0, 140 },
2230 { "make-rslave", 0, 0, 141 },
2231 { "make-rprivate", 0, 0, 142 },
2232 { "make-runbindable", 0, 0, 143 },
2233 { "no-canonicalize", 0, 0, 144 },
2234 { "internal-only", 0, 0, 'i' },
2238 /* Keep the usage message at max 22 lines, each at most 70 chars long.
2239 The user should not need a pager to read it. */
2241 usage (FILE *fp
, int n
) {
2243 "Usage: mount -V : print version\n"
2244 " mount -h : print this help\n"
2245 " mount : list mounted filesystems\n"
2246 " mount -l : idem, including volume labels\n"
2247 "So far the informational part. Next the mounting.\n"
2248 "The command is `mount [-t fstype] something somewhere'.\n"
2249 "Details found in /etc/fstab may be omitted.\n"
2250 " mount -a [-t|-O] ... : mount all stuff from /etc/fstab\n"
2251 " mount device : mount device at the known place\n"
2252 " mount directory : mount known device here\n"
2253 " mount -t type dev dir : ordinary mount command\n"
2254 "Note that one does not really mount a device, one mounts\n"
2255 "a filesystem (of the given type) found on the device.\n"
2256 "One can also mount an already visible directory tree elsewhere:\n"
2257 " mount --bind olddir newdir\n"
2258 "or move a subtree:\n"
2259 " mount --move olddir newdir\n"
2260 "One can change the type of mount containing the directory dir:\n"
2261 " mount --make-shared dir\n"
2262 " mount --make-slave dir\n"
2263 " mount --make-private dir\n"
2264 " mount --make-unbindable dir\n"
2265 "One can change the type of all the mounts in a mount subtree\n"
2266 "containing the directory dir:\n"
2267 " mount --make-rshared dir\n"
2268 " mount --make-rslave dir\n"
2269 " mount --make-rprivate dir\n"
2270 " mount --make-runbindable dir\n"
2271 "A device can be given by name, say /dev/hda1 or /dev/cdrom,\n"
2272 "or by label, using -L label or by uuid, using -U uuid .\n"
2273 "Other options: [-nfFrsvw] [-o options] [-p passwdfd].\n"
2274 "For many more details, say man 8 mount .\n"
2281 /* returns mount entry from fstab */
2282 static struct mntentchn
*
2283 getfs(const char *spec
, const char *uuid
, const char *label
)
2285 struct mntentchn
*mc
= NULL
;
2286 const char *devname
= NULL
;
2288 if (!spec
&& !uuid
&& !label
)
2292 * A) 99% of all cases, the spec on cmdline matches
2293 * with spec in fstab
2296 mc
= getfs_by_uuid(uuid
);
2298 mc
= getfs_by_label(label
);
2300 mc
= getfs_by_spec(spec
);
2303 mc
= getfs_by_dir(spec
);
2309 * B) UUID or LABEL on cmdline, but devname in fstab
2312 devname
= fsprobe_get_devname_by_uuid(uuid
);
2314 devname
= fsprobe_get_devname_by_label(label
);
2316 devname
= spec_to_devname(spec
);
2319 mc
= getfs_by_devname(devname
);
2324 if (!mc
&& devname
) {
2325 const char *id
= NULL
;
2327 if (!label
&& (!spec
|| strncmp(spec
, "LABEL=", 6))) {
2328 id
= fsprobe_get_label_by_devname(devname
);
2330 mc
= getfs_by_label(id
);
2332 if (!mc
&& !uuid
&& (!spec
|| strncmp(spec
, "UUID=", 5))) {
2333 id
= fsprobe_get_uuid_by_devname(devname
);
2335 mc
= getfs_by_uuid(id
);
2340 /* use real device name to avoid repetitional
2341 * conversion from LABEL/UUID to devname
2343 my_free(mc
->m
.mnt_fsname
);
2344 mc
->m
.mnt_fsname
= xstrdup(devname
);
2349 * D) remount -- try /etc/mtab
2350 * Earlier mtab was tried first, but this would sometimes try the
2351 * wrong mount in case mtab had the root device entry wrong. Try
2352 * the last occurrence first, since that is the visible mount.
2354 if (!mc
&& (devname
|| spec
))
2355 mc
= getmntfilebackward (devname
? devname
: spec
, NULL
);
2363 print_version(int rc
) {
2364 printf( "mount from %s (with "
2365 #ifdef HAVE_LIBBLKID
2370 #ifdef HAVE_LIBSELINUX
2373 " support)\n", PACKAGE_STRING
);
2378 main(int argc
, char *argv
[]) {
2379 int c
, result
= 0, specseen
;
2380 char *options
= NULL
, *test_opts
= NULL
, *node
;
2381 const char *spec
= NULL
;
2386 struct mntentchn
*mc
;
2390 setlocale(LC_ALL
, "");
2391 bindtextdomain(PACKAGE
, LOCALEDIR
);
2392 textdomain(PACKAGE
);
2395 if ((p
= strrchr(progname
, '/')) != NULL
)
2400 /* People report that a mount called from init without console
2401 writes error messages to /etc/mtab
2402 Let us try to avoid getting fd's 0,1,2 */
2403 while((fd
= open("/dev/null", O_RDWR
)) == 0 || fd
== 1 || fd
== 2) ;
2409 #ifdef DO_PS_FIDDLING
2410 initproctitle(argc
, argv
);
2413 while ((c
= getopt_long (argc
, argv
, "aBfFhilL:Mno:O:p:rRsU:vVwt:",
2414 longopts
, NULL
)) != -1) {
2416 case 'a': /* mount everything in fstab */
2419 case 'B': /* bind */
2420 mounttype
= MS_BIND
;
2422 case 'f': /* fake: don't actually call mount(2) */
2428 case 'h': /* help */
2432 external_allowed
= 0;
2435 list_with_volumelabel
= 1;
2440 case 'M': /* move */
2441 mounttype
= MS_MOVE
;
2443 case 'n': /* do not write /etc/mtab */
2446 case 'o': /* specify mount options */
2447 options
= append_opt(options
, optarg
, NULL
);
2449 case 'O': /* with -t: mount only if (not) opt */
2450 test_opts
= append_opt(test_opts
, optarg
, NULL
);
2452 case 'p': /* fd on which to read passwd */
2455 case 'r': /* mount readonly */
2459 case 'R': /* rbind */
2460 mounttype
= (MS_BIND
| MS_REC
);
2462 case 's': /* allow sloppy mount options */
2465 case 't': /* specify file system types */
2471 case 'v': /* be chatty - more so if repeated */
2474 case 'V': /* version */
2475 print_version(EXIT_SUCCESS
);
2477 case 'w': /* mount read/write */
2485 /* undocumented, may go away again:
2486 call: mount --guess-fstype device
2487 use only for testing purposes -
2488 the guessing is not reliable at all */
2491 fstype
= fsprobe_get_fstype_by_devname(optarg
);
2492 printf("%s\n", fstype
? fstype
: "unknown");
2493 exit(fstype
? 0 : EX_FAIL
);
2497 mounttype
= MS_SHARED
;
2501 mounttype
= MS_SLAVE
;
2505 mounttype
= MS_PRIVATE
;
2509 mounttype
= MS_UNBINDABLE
;
2513 mounttype
= (MS_SHARED
| MS_REC
);
2517 mounttype
= (MS_SLAVE
| MS_REC
);
2521 mounttype
= (MS_PRIVATE
| MS_REC
);
2525 mounttype
= (MS_UNBINDABLE
| MS_REC
);
2532 usage (stderr
, EX_USAGE
);
2537 printf("mount: fstab path: \"%s\"\n", _PATH_MNTTAB
);
2538 printf("mount: mtab path: \"%s\"\n", _PATH_MOUNTED
);
2539 printf("mount: lock path: \"%s\"\n", _PATH_MOUNTED_LOCK
);
2540 printf("mount: temp path: \"%s\"\n", _PATH_MOUNTED_TMP
);
2541 printf("mount: UID: %u\n", getuid());
2542 printf("mount: eUID: %u\n", geteuid());
2545 #ifdef HAVE_LIBMOUNT_MOUNT
2551 specseen
= (uuid
|| label
) ? 1 : 0; /* yes, .. i know */
2553 if (argc
+specseen
== 0 && !mount_all
) {
2554 if (options
|| mounttype
)
2555 usage (stderr
, EX_USAGE
);
2556 return print_all (types
);
2560 const uid_t ruid
= getuid();
2561 const uid_t euid
= geteuid();
2563 /* if we're really root and aren't running setuid */
2564 if (((uid_t
)0 == ruid
) && (ruid
== euid
)) {
2569 (types
|| options
|| readwrite
|| nomtab
|| mount_all
||
2570 nocanonicalize
|| fake
|| mounttype
||
2571 (argc
+ specseen
) != 1)) {
2573 if (ruid
== 0 && euid
!= 0)
2574 /* user is root, but setuid to non-root */
2575 die (EX_USAGE
, _("mount: only root can do that "
2576 "(effective UID is %u)"), euid
);
2578 die (EX_USAGE
, _("mount: only root can do that"));
2582 atexit(unlock_mtab
);
2584 switch (argc
+specseen
) {
2587 result
= do_mount_all (types
, options
, test_opts
);
2588 if (result
== 0 && verbose
&& !fake
)
2589 error(_("nothing was mounted"));
2593 /* mount [-nfrvw] [-o options] special | node
2594 * mount -L label (or -U uuid)
2595 * (/etc/fstab is necessary)
2598 usage (stderr
, EX_USAGE
);
2601 mc
= getfs(NULL
, uuid
, label
);
2603 mc
= getfs(*argv
, NULL
, NULL
);
2607 die (EX_USAGE
, _("mount: no such partition found"));
2610 _("mount: can't find %s in %s or %s"),
2611 *argv
, _PATH_MNTTAB
, _PATH_MOUNTED
);
2614 result
= mount_one (xstrdup (mc
->m
.mnt_fsname
),
2615 xstrdup (mc
->m
.mnt_dir
),
2616 xstrdup (mc
->m
.mnt_type
),
2617 mc
->m
.mnt_opts
, options
, 0, 0);
2621 /* mount special node (/etc/fstab is not necessary) */
2623 /* mount -L label node (or -U uuid) */
2624 spec
= uuid
? fsprobe_get_devname_by_uuid(uuid
) :
2625 fsprobe_get_devname_by_label(label
);
2628 /* mount special node */
2633 die (EX_USAGE
, _("mount: no such partition found"));
2635 result
= mount_one (spec
, node
, types
, NULL
, options
, 0, 0);
2639 usage (stderr
, EX_USAGE
);
2642 if (result
== EX_SOMEOK
)