]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - mount/mount.c
2 * A mount(8) for Linux 0.99.
3 * mount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
5 * Wed Sep 14 22:43:00 1994: Mitchum DSouza
6 * (mitch@mrc-applied-psychology.cambridge.ac.uk) added support for mounting
9 * Wed Sep 14 22:55:10 1994: Sander van Malssen (svm@kozmix.hacktic.nl)
10 * added support for remounting readonly file systems readonly.
12 * Wed Feb 8 12:27:00 1995: Andries.Brouwer@cwi.nl fixed up error messages.
13 * Sat Jun 3 20:44:38 1995: Patches from Andries.Brouwer@cwi.nl applied.
14 * Tue Sep 26 22:38:20 1995: aeb@cwi.nl, many changes
15 * Fri Feb 23 13:47:00 1996: aeb@cwi.nl, loop device related changes
17 * Since then, many changes - aeb.
19 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
20 * Implemented the "bg", "fg" and "retry" mount options for NFS.
22 * Tue Aug 4 15:54:31 1998: aeb@cwi.nl:
23 * Open fd 0,1,2 so that printf's do not clobber /etc/mtab or so.
24 * Mangle filenames with embedded spaces. Add ufsmagic. Add locking.
25 * Avoid unnecessary error messages about /proc.
26 * Improve support for noncanonical names in /etc/fstab.
27 * Add support for volume labels and UUIDs.
29 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
30 * - added Native Language Support
31 * 1999-03-21 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
32 * - fixed strerr(errno) in gettext calls
33 * 1999-07-05 Hirokazu Takahashi <h-takaha@sss.abk.nec.co.jp>
34 * - fixed use of nouser option
35 * 1999-09-09 Michael K. Johnson <johnsonm@redhat.com>
36 * - added `owner' mount option
37 * 2000-05-11 Mark A. Peloquin <peloquin@us.ibm.com>
38 * - check_special_mountprog now returns correct status
39 * 2000-11-08 aeb: accept nonnumeric uid=, gid= options
52 #include <sys/types.h>
53 #include <sys/ioctl.h>
56 #include <sys/mount.h>
58 #include "mount_constants.h"
64 #include "linux_fs.h" /* for BLKGETSIZE */
65 #include "mount_guess_rootdev.h"
66 #include "mount_guess_fstype.h"
67 #include "mount_by_label.h"
68 #include "getusername.h"
71 #define DO_PS_FIDDLING
74 #include "setproctitle.h"
77 /* True for fake mount (-f). */
80 /* Don't write a entry in /etc/mtab (-n). */
81 static int nomtab
= 0;
83 /* True for explicit readonly (-r). */
84 static int readonly
= 0;
86 /* Nonzero for chatty (-v). */
89 /* Nonzero for sloppy (-s). */
92 /* True for explicit read/write (-w). */
93 static int readwrite
= 0;
95 /* True for all mount (-a). */
98 /* True for fork() during all mount (-F). */
99 static int optfork
= 0;
101 /* Add volumelabel in a listing of mounted devices (-l). */
102 static int list_with_volumelabel
= 0;
104 /* Nonzero for mount --bind */
107 /* Nonzero for mount {--replace|--before|--after|--over} */
108 static int mounttype
= 0;
110 /* True if ruid != euid. */
113 /* Map from -o and fstab option strings to the flag argument to mount(2). */
115 const char *opt
; /* option name */
116 int skip
; /* skip in mtab option string */
117 int inv
; /* true if flag value should be inverted */
118 int mask
; /* flag mask value */
121 /* Custom mount options for our own purposes. */
122 /* Maybe these should now be freed for kernel use again */
123 #define MS_NOAUTO 0x80000000
124 #define MS_USERS 0x40000000
125 #define MS_USER 0x20000000
126 #define MS_OWNER 0x10000000
127 #define MS_LOOP 0x00010000
129 /* Options that we keep the mount system call from seeing. */
130 #define MS_NOSYS (MS_NOAUTO|MS_USERS|MS_USER|MS_LOOP)
132 /* Options that we keep from appearing in the options field in the mtab. */
133 #define MS_NOMTAB (MS_REMOUNT|MS_NOAUTO|MS_USERS|MS_USER)
135 /* Options that we make ordinary users have by default. */
136 #define MS_SECURE (MS_NOEXEC|MS_NOSUID|MS_NODEV)
138 /* Options that we make owner-mounted devices have by default */
139 #define MS_OWNERSECURE (MS_NOSUID|MS_NODEV)
141 static const struct opt_map opt_map
[] = {
142 { "defaults", 0, 0, 0 }, /* default options */
143 { "ro", 1, 0, MS_RDONLY
}, /* read-only */
144 { "rw", 1, 1, MS_RDONLY
}, /* read-write */
145 { "exec", 0, 1, MS_NOEXEC
}, /* permit execution of binaries */
146 { "noexec", 0, 0, MS_NOEXEC
}, /* don't execute binaries */
147 { "suid", 0, 1, MS_NOSUID
}, /* honor suid executables */
148 { "nosuid", 0, 0, MS_NOSUID
}, /* don't honor suid executables */
149 { "dev", 0, 1, MS_NODEV
}, /* interpret device files */
150 { "nodev", 0, 0, MS_NODEV
}, /* don't interpret devices */
151 { "sync", 0, 0, MS_SYNCHRONOUS
}, /* synchronous I/O */
152 { "async", 0, 1, MS_SYNCHRONOUS
}, /* asynchronous I/O */
153 { "remount", 0, 0, MS_REMOUNT
}, /* Alter flags of mounted FS */
154 { "bind", 0, 0, MS_BIND
}, /* Remount part of tree elsewhere */
155 { "auto", 0, 1, MS_NOAUTO
}, /* Can be mounted using -a */
156 { "noauto", 0, 0, MS_NOAUTO
}, /* Can only be mounted explicitly */
157 { "users", 0, 0, MS_USERS
}, /* Allow ordinary user to mount */
158 { "nousers", 0, 1, MS_USERS
}, /* Forbid ordinary user to mount */
159 { "user", 0, 0, MS_USER
}, /* Allow ordinary user to mount */
160 { "nouser", 0, 1, MS_USER
}, /* Forbid ordinary user to mount */
161 { "owner", 0, 0, MS_OWNER
}, /* Let the owner of the device mount */
162 { "noowner", 0, 1, MS_OWNER
}, /* Device owner has no special privs */
163 /* add new options here */
165 { "sub", 0, 1, MS_NOSUB
}, /* allow submounts */
166 { "nosub", 0, 0, MS_NOSUB
}, /* don't allow submounts */
169 { "quiet", 0, 0, MS_SILENT
}, /* be quiet */
170 { "loud", 0, 1, MS_SILENT
}, /* print out messages. */
173 { "mand", 0, 0, MS_MANDLOCK
}, /* Allow mandatory locks on this FS */
174 { "nomand", 0, 1, MS_MANDLOCK
}, /* Forbid mandatory locks on this FS */
176 { "loop", 1, 0, MS_LOOP
}, /* use a loop device */
178 { "atime", 0, 1, MS_NOATIME
}, /* Update access time */
179 { "noatime", 0, 0, MS_NOATIME
}, /* Do not update access time */
182 { "diratime", 0, 1, MS_NODIRATIME
}, /* Update dir access times */
183 { "nodiratime", 0, 0, MS_NODIRATIME
},/* Do not update dir access times */
188 static char *opt_loopdev
, *opt_vfstype
, *opt_offset
, *opt_encryption
,
191 static struct string_opt_map
{
195 } string_opt_map
[] = {
196 { "loop=", 0, &opt_loopdev
},
197 { "vfs=", 1, &opt_vfstype
},
198 { "offset=", 0, &opt_offset
},
199 { "encryption=", 0, &opt_encryption
},
200 { "speed=", 0, &opt_speed
},
205 clear_string_opts(void) {
206 struct string_opt_map
*m
;
208 for (m
= &string_opt_map
[0]; m
->tag
; m
++)
213 parse_string_opt(char *s
) {
214 struct string_opt_map
*m
;
217 for (m
= &string_opt_map
[0]; m
->tag
; m
++) {
218 lth
= strlen(m
->tag
);
219 if (!strncmp(s
, m
->tag
, lth
)) {
220 *(m
->valptr
) = xstrdup(s
+ lth
);
229 /* Report on a single mount. */
231 print_one (const struct mntent
*me
) {
234 printf ("%s on %s", me
->mnt_fsname
, me
->mnt_dir
);
235 if (me
->mnt_type
!= NULL
&& *(me
->mnt_type
) != '\0')
236 printf (" type %s", me
->mnt_type
);
237 if (me
->mnt_opts
!= NULL
)
238 printf (" (%s)", me
->mnt_opts
);
239 if (list_with_volumelabel
) {
241 label
= get_volume_label_by_spec(me
->mnt_fsname
);
243 printf (" [%s]", label
);
248 /* Report on everything in mtab (of the specified types if any). */
250 print_all (string_list types
) {
251 struct mntentchn
*mc
, *mc0
;
254 for (mc
= mc0
->nxt
; mc
&& mc
!= mc0
; mc
= mc
->nxt
) {
255 if (matching_type (mc
->m
.mnt_type
, types
))
256 print_one (&(mc
->m
));
263 * Look for OPT in opt_map table and return mask value.
264 * If OPT isn't found, tack it onto extra_opts (which is non-NULL).
265 * For the options uid= and gid= replace user or group name by its value.
268 parse_opt (const char *opt
, int *mask
, char *extra_opts
) {
269 const struct opt_map
*om
;
271 for (om
= opt_map
; om
->opt
!= NULL
; om
++)
272 if (streq (opt
, om
->opt
)) {
277 if ((om
->mask
== MS_USER
|| om
->mask
== MS_USERS
)
280 if ((om
->mask
== MS_OWNER
) && !om
->inv
)
281 *mask
|= MS_OWNERSECURE
;
283 if (om
->mask
== MS_SILENT
&& om
->inv
) {
292 strcat(extra_opts
, ",");
294 /* convert nonnumeric ids to numeric */
295 if (!strncmp(opt
, "uid=", 4) && !isdigit(opt
[4])) {
296 struct passwd
*pw
= getpwnam(opt
+4);
300 sprintf(uidbuf
, "uid=%d", pw
->pw_uid
);
301 strcat(extra_opts
, uidbuf
);
305 if (!strncmp(opt
, "gid=", 4) && !isdigit(opt
[4])) {
306 struct group
*gr
= getgrnam(opt
+4);
310 sprintf(gidbuf
, "gid=%d", gr
->gr_gid
);
311 strcat(extra_opts
, gidbuf
);
316 strcat(extra_opts
, opt
);
319 /* Take -o options list and compute 4th and 5th args to mount(2). flags
320 gets the standard options (indicated by bits) and extra_opts all the rest */
322 parse_opts (char *opts
, int *flags
, char **extra_opts
) {
331 *extra_opts
= xmalloc (strlen (opts
) + 1);
334 for (opt
= strtok (opts
, ","); opt
; opt
= strtok (NULL
, ","))
335 if (!parse_string_opt (opt
))
336 parse_opt (opt
, flags
, *extra_opts
);
342 *flags
&= ~MS_RDONLY
;
348 /* Try to build a canonical options string. */
350 fix_opts_string (int flags
, const char *extra_opts
, const char *user
) {
351 const struct opt_map
*om
;
352 const struct string_opt_map
*m
;
355 new_opts
= (flags
& MS_RDONLY
) ? "ro" : "rw";
356 for (om
= opt_map
; om
->opt
!= NULL
; om
++) {
359 if (om
->inv
|| !om
->mask
|| (flags
& om
->mask
) != om
->mask
)
361 new_opts
= xstrconcat3(new_opts
, ",", om
->opt
);
364 for (m
= &string_opt_map
[0]; m
->tag
; m
++) {
365 if (!m
->skip
&& *(m
->valptr
))
366 new_opts
= xstrconcat4(new_opts
, ",", m
->tag
, *(m
->valptr
));
368 if (extra_opts
&& *extra_opts
) {
369 new_opts
= xstrconcat3(new_opts
, ",", extra_opts
);
372 new_opts
= xstrconcat3(new_opts
, ",user=", user
);
378 already (const char *spec
, const char *node
) {
379 struct mntentchn
*mc
;
382 if ((mc
= getmntfile(node
)) != NULL
)
383 error (_("mount: according to mtab, %s is already mounted on %s"),
384 mc
->m
.mnt_fsname
, node
);
385 else if (spec
&& strcmp (spec
, "none") &&
386 (mc
= getmntfile(spec
)) != NULL
)
387 error (_("mount: according to mtab, %s is mounted on %s"),
388 spec
, mc
->m
.mnt_dir
);
394 /* Create mtab with a root entry. */
397 struct mntentchn
*fstab
;
405 mfp
= my_setmntent (MOUNTED
, "a+");
406 if (mfp
== NULL
|| mfp
->mntent_fp
== NULL
) {
408 die (EX_FILEIO
, _("mount: can't open %s for writing: %s"),
409 MOUNTED
, strerror (errsv
));
412 /* Find the root entry by looking it up in fstab */
413 if ((fstab
= getfsfile ("/")) || (fstab
= getfsfile ("root"))) {
414 parse_opts (xstrdup (fstab
->m
.mnt_opts
), &flags
, &extra_opts
);
416 mnt
.mnt_fsname
= canonicalize (fstab
->m
.mnt_fsname
);
417 mnt
.mnt_type
= fstab
->m
.mnt_type
;
418 mnt
.mnt_opts
= fix_opts_string (flags
, extra_opts
, NULL
);
419 mnt
.mnt_freq
= mnt
.mnt_passno
= 0;
421 if (my_addmntent (mfp
, &mnt
) == 1) {
423 die (EX_FILEIO
, _("mount: error writing %s: %s"),
424 MOUNTED
, strerror (errsv
));
427 if (fchmod (fileno (mfp
->mntent_fp
), S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IROTH
) < 0)
428 if (errno
!= EROFS
) {
430 die (EX_FILEIO
, _("mount: error changing mode of %s: %s"),
431 MOUNTED
, strerror (errsv
));
438 /* count successful mount system calls */
439 static int mountcount
= 0;
443 * Mount a single file system. Keep track of successes.
444 * returns: 0: OK, -1: error in errno
447 do_mount_syscall (struct mountargs
*args
) {
448 int ret
= mount (args
->spec
, args
->node
, args
->type
,
449 MS_MGC_VAL
| (args
->flags
), args
->data
);
456 * guess_fstype_and_mount()
457 * Mount a single file system. Guess the type when unknown.
458 * returns: 0: OK, -1: error in errno, 1: other error
459 * don't exit on non-fatal errors.
462 guess_fstype_and_mount (char *spec
, char *node
, char **type
,
463 int flags
, char *mount_opts
) {
464 struct mountargs args
= { spec
, node
, NULL
, flags
& ~MS_NOSYS
, mount_opts
};
466 if (*type
&& strcasecmp (*type
, "auto") == 0)
469 if (!*type
&& (flags
& MS_BIND
))
470 *type
= "none"; /* random, but not "bind" */
472 if (!*type
&& !(flags
& MS_REMOUNT
)) {
473 *type
= guess_fstype_from_superblock(spec
);
474 if (*type
&& !strcmp(*type
, "swap")) {
475 error(_("%s looks like swapspace - not mounted"), spec
);
481 if (*type
|| (flags
& MS_REMOUNT
)) {
483 return do_mount_syscall (&args
);
486 return procfsloop(do_mount_syscall
, &args
, type
);
491 * Die if the user is not allowed to do this.
494 suid_check(char *spec
, char *node
, int *flags
, char **user
) {
496 /* RedHat patch: allow owners to mount when fstab contains
497 the owner option. Note that this should never be used
498 in a high security environment, but may be useful to give
499 people at the console the possibility of mounting a floppy. */
500 if (*flags
& MS_OWNER
) {
501 if (!strncmp(spec
, "/dev/", 5)) {
504 if (!stat(spec
, &sb
)) {
505 if (getuid() == sb
.st_uid
)
510 /* James Kehl <mkehl@gil.com.au> came with a similar patch:
511 allow an arbitrary user to mount when he is the owner of
512 the mount-point and has write-access to the device.
513 This is even less secure. Let me skip it for the time being;
514 there should be an explicit fstab line allowing such things. */
516 if (!(*flags
& (MS_USER
| MS_USERS
))) {
517 if (already (spec
, node
))
518 die (EX_USAGE
, _("mount failed"));
520 die (EX_USAGE
, _("mount: only root can mount %s on %s"), spec
, node
);
522 if (*flags
& MS_USER
)
523 *user
= getusername();
526 if (*flags
& MS_OWNER
)
531 loop_check(char **spec
, char **type
, int *flags
,
532 int *loop
, char **loopdev
, char **loopfile
) {
533 int looptype
, offset
;
536 * In the case of a loop mount, either type is of the form lo@/dev/loop5
537 * or the option "-o loop=/dev/loop5" or just "-o loop" is given, or
538 * mount just has to figure things out for itself from the fact that
539 * spec is not a block device. We do not test for a block device
540 * immediately: maybe later other types of mountable objects will occur.
543 *loopdev
= opt_loopdev
;
545 looptype
= (*type
&& strncmp("lo@", *type
, 3) == 0);
548 error(_("mount: loop device specified twice"));
549 *loopdev
= *type
+ 3;
551 } else if (opt_vfstype
) {
553 error(_("mount: type specified twice"));
558 *loop
= ((*flags
& MS_LOOP
) || *loopdev
|| opt_offset
|| opt_encryption
);
565 printf(_("mount: skipping the setup of a loop device\n"));
567 int loopro
= (*flags
& MS_RDONLY
);
569 if (!*loopdev
|| !**loopdev
)
570 *loopdev
= find_unused_loop_device();
572 return EX_SYSERR
; /* no more loop devices */
574 printf(_("mount: going to use the loop device %s\n"), *loopdev
);
575 offset
= opt_offset
? strtoul(opt_offset
, NULL
, 0) : 0;
576 if (set_loop (*loopdev
, *loopfile
, offset
, opt_encryption
, &loopro
)) {
578 printf(_("mount: failed setting up loop device\n"));
582 printf(_("mount: setup loop device successfully\n"));
593 update_mtab_entry(char *spec
, char *node
, char *type
, char *opts
,
594 int flags
, int freq
, int pass
) {
597 mnt
.mnt_fsname
= canonicalize (spec
);
598 mnt
.mnt_dir
= canonicalize (node
);
602 mnt
.mnt_passno
= pass
;
604 /* We get chatty now rather than after the update to mtab since the
605 mount succeeded, even if the write to /etc/mtab should fail. */
609 if (!nomtab
&& mtab_is_writable()) {
610 if (flags
& MS_REMOUNT
)
611 update_mtab (mnt
.mnt_dir
, &mnt
);
616 mfp
= my_setmntent(MOUNTED
, "a+");
617 if (mfp
== NULL
|| mfp
->mntent_fp
== NULL
) {
619 error(_("mount: can't open %s: %s"), MOUNTED
,
622 if ((my_addmntent (mfp
, &mnt
)) == 1) {
624 error(_("mount: error writing %s: %s"), MOUNTED
,
635 cdrom_setspeed(char *spec
) {
636 #define CDROM_SELECT_SPEED 0x5322 /* Set the CD-ROM speed */
639 int speed
= atoi(opt_speed
);
641 if ((cdrom
= open(spec
, O_RDONLY
| O_NONBLOCK
)) < 0)
642 die(EX_FAIL
, _("mount: cannot not open %s for setting speed"),
644 if (ioctl(cdrom
, CDROM_SELECT_SPEED
, speed
) < 0)
645 die(EX_FAIL
, _("mount: cannot set speed: %s"),
652 * check_special_mountprog()
653 * If there is a special mount program for this type, exec it.
654 * returns: 0: no exec was done, 1: exec was done, status has result
659 check_special_mountprog(char *spec
, char *node
, char *type
, int flags
,
660 char *extra_opts
, int *status
) {
667 (streq (type
, "smb") || streq (type
, "ncp")
668 /* these are incorrect but perhaps used by smbmount or so */
669 || streq (type
, "smbfs") || streq (type
, "ncpfs")
672 (strlen (type
) < 100)
675 sprintf(mountprog
, "/sbin/mount.%s", type
);
676 if (stat(mountprog
, &statbuf
) == 0) {
679 char *oo
, *mountargs
[10];
684 oo
= fix_opts_string (flags
, extra_opts
, NULL
);
685 mountargs
[i
++] = mountprog
;
686 mountargs
[i
++] = spec
;
687 mountargs
[i
++] = node
;
689 mountargs
[i
++] = "-n";
691 mountargs
[i
++] = "-v";
693 mountargs
[i
++] = "-o";
697 execv(mountprog
, mountargs
);
698 exit(1); /* exec failed */
699 } else if (res
!= -1) {
702 *status
= (WIFEXITED(st
) ? WEXITSTATUS(st
) : EX_SYSERR
);
706 error(_("mount: cannot fork: %s"), strerror(errsv
));
715 * Try to mount one file system. When "bg" is 1, this is a retry
716 * in the background. One additional exit code EX_BG is used here.
717 * It is used to instruct the caller to retry the mount in the
719 * returns: 0: OK, EX_SYSERR, EX_FAIL, return code from nfsmount,
720 * return status from wait
723 try_mount_one (const char *spec0
, const char *node0
, char *type0
,
724 const char *opts0
, int freq
, int pass
, int bg
, int ro
) {
726 int mnt5_res
= 0; /* only for gcc */
729 char *extra_opts
; /* written in mtab */
730 char *mount_opts
; /* actually used on system call */
732 char *spec
, *node
, *type
;
735 char *loopdev
= 0, *loopfile
= 0;
738 spec
= xstrdup(spec0
);
739 node
= xstrdup(node0
);
740 type
= xstrdup(type0
);
741 opts
= xstrdup(opts0
);
743 parse_opts (xstrdup (opts
), &flags
, &extra_opts
);
745 suid_check (spec
, node
, &flags
, &user
);
747 /* quietly succeed for fstab entries that don't get mounted automatically */
748 if (all
&& (flags
& MS_NOAUTO
))
751 mount_opts
= extra_opts
;
754 cdrom_setspeed(spec
);
756 if (!(flags
& MS_REMOUNT
)) {
757 /* don't set up a (new) loop device if we only remount - this left
758 * stale assignments of files to loop devices. Nasty when used for
761 res
= loop_check (&spec
, &type
, &flags
, &loop
, &loopdev
, &loopfile
);
767 * Call mount.TYPE for types that require a separate mount program.
768 * For the moment these types are ncp and smb.
770 if (check_special_mountprog (spec
, node
, type
, flags
, extra_opts
, &status
))
773 if (!fake
&& type
&& streq (type
, "nfs")) {
776 mnt_err
= nfsmount (spec
, node
, &flags
, &extra_opts
, &mount_opts
, bg
);
780 die (EX_SOFTWARE
, _("mount: this version was compiled "
781 "without support for the type `nfs'"));
785 block_signals (SIG_BLOCK
);
788 mnt5_res
= guess_fstype_and_mount (spec
, node
, &type
, flags
& ~MS_NOSYS
,
791 if (fake
|| mnt5_res
== 0) {
792 /* Mount succeeded, report this (if verbose) and write mtab entry. */
794 opt_loopdev
= loopdev
;
796 update_mtab_entry(loop
? loopfile
: spec
,
798 type
? type
: "unknown",
799 fix_opts_string (flags
& ~MS_NOMTAB
, extra_opts
, user
),
804 block_signals (SIG_UNBLOCK
);
813 block_signals (SIG_UNBLOCK
);
816 if (mnt_err
&& type
&& streq (type
, "nfs")) {
817 extern int nfs_mount_version
;
818 if (nfs_mount_version
== 4) {
820 printf(_("mount: failed with nfs mount version 4, trying 3..\n"));
821 nfs_mount_version
= 3;
827 /* Mount failed, complain, but don't die. */
831 error (_("mount: I could not determine the filesystem type, "
832 "and none was specified"));
834 error (_("mount: you must specify the filesystem type"));
835 } else if (mnt5_res
!= -1) {
836 /* should not happen */
837 error (_("mount: mount failed"));
841 if (geteuid() == 0) {
842 if (stat (node
, &statbuf
) || !S_ISDIR(statbuf
.st_mode
))
843 error (_("mount: mount point %s is not a directory"), node
);
845 error (_("mount: permission denied"));
847 error (_("mount: must be superuser to use mount"));
850 if (flags
& MS_REMOUNT
) {
851 error (_("mount: %s is busy"), node
);
852 } else if (!strcmp(type
, "proc") && !strcmp(node
, "/proc")) {
853 /* heuristic: if /proc/version exists, then probably proc is mounted */
854 if (stat ("/proc/version", &statbuf
)) /* proc mounted? */
855 error (_("mount: %s is busy"), node
); /* no */
856 else if(!all
|| verbose
) /* yes, don't mention it */
857 error (_("mount: proc already mounted"));
859 error (_("mount: %s already mounted or %s busy"), spec
, node
);
860 already (spec
, node
);
864 if (lstat (node
, &statbuf
))
865 error (_("mount: mount point %s does not exist"), node
);
866 else if (stat (node
, &statbuf
))
867 error (_("mount: mount point %s is a symbolic link to nowhere"),
869 else if (stat (spec
, &statbuf
))
870 error (_("mount: special device %s does not exist"), spec
);
877 if (stat (node
, &statbuf
) || ! S_ISDIR(statbuf
.st_mode
))
878 error (_("mount: mount point %s is not a directory"), node
);
879 else if (stat (spec
, &statbuf
) && errno
== ENOTDIR
)
880 error (_("mount: special device %s does not exist\n"
881 " (a path prefix is not a directory)\n"), spec
);
892 if (flags
& MS_REMOUNT
) {
893 error (_("mount: %s not mounted already, or bad option"), node
);
895 error (_("mount: wrong fs type, bad option, bad superblock on %s,\n"
896 " or too many mounted file systems"),
899 if (stat (spec
, &statbuf
) == 0 && S_ISBLK(statbuf
.st_mode
)
900 && (fd
= open(spec
, O_RDONLY
| O_NONBLOCK
)) >= 0) {
901 if(ioctl(fd
, BLKGETSIZE
, &size
) == 0) {
904 error (" (could this be the IDE device where you in fact use\n"
905 " ide-scsi so that sr0 or sda or so is needed?)");
907 if (size
&& size
<= 2) {
909 error (" (aren't you trying to mount an extended partition,\n"
910 " instead of some logical partition inside?)");
915 /* 0xf for SCSI, 0x3f for IDE. One might check /proc/partitions
916 to see whether this thing really is partitioned.
917 Do not suggest partitions for /dev/fd0. */
918 if (!warned
&& (statbuf
.st_rdev
& 0xf) == 0) {
920 error (" (could this be the whole disk device\n"
921 " where you need a partition?)");
929 error (_("mount table full")); break;
931 error (_("mount: %s: can't read superblock"), spec
); break;
934 if ((pfs
= is_in_procfs(type
)) == 1 || !strcmp(type
, "guess"))
935 error(_("mount: %s: unknown device"), spec
);
940 error (_("mount: fs type %s not supported by kernel"), type
);
942 /* maybe this loser asked for FAT or ISO9660 or isofs */
943 lowtype
= xstrdup(type
);
945 for(p
=lowtype
; *p
; p
++) {
946 if(tolower(*p
) != *p
) {
951 if (u
&& is_in_procfs(lowtype
) == 1)
952 error (_("mount: probably you meant %s"), lowtype
);
953 else if (!strncmp(lowtype
, "iso", 3) && is_in_procfs("iso9660") == 1)
954 error (_("mount: maybe you meant iso9660 ?"));
957 error (_("mount: %s has wrong device number or fs type %s not supported"),
962 if (stat (spec
, &statbuf
)) /* strange ... */
963 error (_("mount: %s is not a block device, and stat fails?"), spec
);
964 else if (S_ISBLK(statbuf
.st_mode
))
965 error (_("mount: the kernel does not recognize %s as a block device\n"
966 " (maybe `insmod driver'?)"), spec
);
967 else if (S_ISREG(statbuf
.st_mode
))
968 error (_("mount: %s is not a block device (maybe try `-o loop'?)"),
971 error (_("mount: %s is not a block device"), spec
);
974 error (_("mount: %s is not a valid block device"), spec
); break;
975 case EACCES
: /* pre-linux 1.1.38, 1.1.41 and later */
976 case EROFS
: /* linux 1.1.38 and later */
977 { char *bd
= (loop
? "" : _("block device "));
978 if (ro
|| (flags
& MS_RDONLY
)) {
979 error (_("mount: cannot mount %s%s read-only"),
982 } else if (readwrite
) {
983 error (_("mount: %s%s is write-protected but explicit `-w' flag given"),
992 char *opts1
= realloc(xstrdup(opts
), strlen(opts
)+4);
993 strcat(opts1
, ",ro");
997 if (type
&& !strcmp(type
, "guess"))
999 error (_("mount: %s%s is write-protected, mounting read-only"),
1001 return try_mount_one (spec0
, node0
, type
, opts
, freq
, pass
, bg
, 1);
1006 error ("mount: %s", strerror (mnt_err
)); break;
1014 * Update the argument vector, so that this process may be easily
1015 * identified in a "ps" listing.
1018 set_proc_name (const char *spec
)
1020 #ifdef DO_PS_FIDDLING
1021 setproctitle ("mount", spec
);
1026 subst_string(const char *s
, const char *sub
, int sublen
, const char *repl
) {
1029 n
= (char *) xmalloc(strlen(s
)-sublen
+strlen(repl
)+1);
1030 strncpy (n
, s
, sub
-s
);
1031 strcpy (n
+ (sub
-s
), repl
);
1032 strcat (n
, sub
+sublen
);
1037 usersubst(const char *opts
) {
1042 if (opts
&& (w
= strstr(opts
, s
)) != NULL
) {
1043 sprintf(id
, "uid=%d", getuid());
1044 opts
= subst_string(opts
, w
, strlen(s
), id
);
1047 if (opts
&& (w
= strstr(opts
, s
)) != NULL
) {
1048 sprintf(id
, "gid=%d", getgid());
1049 opts
= subst_string(opts
, w
, strlen(s
), id
);
1056 * Return 0 for success (either mounted sth or -a and NOAUTO was given)
1059 mount_one (const char *spec
, const char *node
, char *type
, const char *opts
,
1060 char *cmdlineopts
, int freq
, int pass
) {
1066 /* Substitute values in opts, if required */
1067 opts
= usersubst(opts
);
1069 /* Merge the fstab and command line options. */
1072 else if (cmdlineopts
!= NULL
)
1073 opts
= xstrconcat3(opts
, ",", cmdlineopts
);
1075 if (!strncmp(spec
, "UUID=", 5)) {
1076 nspec
= get_spec_by_uuid(spec
+5);
1078 } else if (!strncmp(spec
, "LABEL=", 6)) {
1079 nspec
= get_spec_by_volume_label(spec
+6);
1082 nspec
= 0; /* just for gcc */
1088 printf(_("mount: going to mount %s by %s\n"), spec
,
1089 (specset
==1) ? _("UUID") : _("label"));
1091 die (EX_USAGE
, _("mount: no such partition found"));
1092 /* if -a then we may be rescued by a noauto option */
1095 if (type
== NULL
&& !bind
) {
1096 if (strchr (spec
, ':') != NULL
) {
1099 printf(_("mount: no type was given - "
1100 "I'll assume nfs because of the colon\n"));
1105 * Try to mount the file system. When the exit status is EX_BG,
1106 * we will retry in the background. Otherwise, we're done.
1108 status
= try_mount_one (spec
, node
, type
, opts
, freq
, pass
, 0, 0);
1109 if (status
!= EX_BG
)
1113 * Retry in the background.
1115 printf (_("mount: backgrounding \"%s\"\n"), spec
);
1116 fflush( stdout
); /* prevent duplicate output */
1118 return 0; /* parent returns "success" */
1119 spec
= xstrdup(spec
); /* arguments will be destroyed */
1120 node
= xstrdup(node
); /* by set_proc_name() */
1121 type
= xstrdup(type
);
1122 opts
= xstrdup(opts
);
1123 set_proc_name (spec
); /* make a nice "ps" listing */
1124 status2
= try_mount_one (spec
, node
, type
, opts
, freq
, pass
, 1, 0);
1125 if (verbose
&& status2
)
1126 printf (_("mount: giving up \"%s\"\n"), spec
);
1127 exit (0); /* child stops here */
1130 /* Check if an fsname/dir pair was already in the old mtab. */
1132 mounted (char *spec
, char *node
) {
1133 struct mntentchn
*mc
, *mc0
;
1136 if (!strncmp(spec
, "UUID=", 5))
1137 nspec
= get_spec_by_uuid(spec
+5);
1138 else if (!strncmp(spec
, "LABEL=", 6))
1139 nspec
= get_spec_by_volume_label(spec
+6);
1144 spec
= canonicalize (spec
);
1145 node
= canonicalize (node
);
1148 for (mc
= mc0
->nxt
; mc
&& mc
!= mc0
; mc
= mc
->nxt
)
1149 if (streq (spec
, mc
->m
.mnt_fsname
) && streq (node
, mc
->m
.mnt_dir
))
1154 /* Mount all filesystems of the specified types except swap and root. */
1155 /* With the --fork option: fork and let different incarnations of
1156 mount handle different filesystems. However, try to avoid several
1157 simultaneous mounts on the same physical disk, since that is very slow. */
1158 #define DISKMAJOR(m) (((int) m) & ~0xf)
1161 mount_all (string_list types
, char *options
) {
1162 struct mntentchn
*mc
, *mc0
, *mtmp
;
1164 struct stat statbuf
;
1168 struct mntentchn
*mec
;
1169 struct mntentchn
*meclast
;
1171 } childhead
, *childtail
, *cp
;
1175 /* build a chain of what we have to do, or maybe
1176 several chains, one for each major or NFS host */
1178 childtail
= &childhead
;
1180 for (mc
= mc0
->nxt
; mc
&& mc
!= mc0
; mc
= mc
->nxt
) {
1181 if (matching_type (mc
->m
.mnt_type
, types
)
1182 && !streq (mc
->m
.mnt_dir
, "/")
1183 && !streq (mc
->m
.mnt_dir
, "root")) {
1184 if (mounted (mc
->m
.mnt_fsname
, mc
->m
.mnt_dir
)) {
1186 printf(_("mount: %s already mounted on %s\n"),
1187 mc
->m
.mnt_fsname
, mc
->m
.mnt_dir
);
1189 mtmp
= (struct mntentchn
*) xmalloc(sizeof(*mtmp
));
1194 if (stat(mc
->m
.mnt_fsname
, &statbuf
) == 0 &&
1195 S_ISBLK(statbuf
.st_mode
)) {
1196 sprintf(major
, "#%x", DISKMAJOR(statbuf
.st_rdev
));
1200 if (strcmp(mc
->m
.mnt_type
, "nfs") == 0) {
1201 g
= xstrdup(mc
->m
.mnt_fsname
);
1202 colon
= strchr(g
, ':');
1209 for (cp
= childhead
.nxt
; cp
; cp
= cp
->nxt
)
1210 if (cp
->group
&& strcmp(cp
->group
, g
) == 0) {
1211 cp
->meclast
->nxt
= mtmp
;
1216 cp
= (struct child
*) xmalloc(sizeof *cp
);
1218 cp
->mec
= cp
->meclast
= mtmp
;
1219 cp
->group
= xstrdup(g
);
1221 childtail
->nxt
= cp
;
1228 /* now do everything */
1229 for (cp
= childhead
.nxt
; cp
; cp
= cp
->nxt
) {
1235 error(_("mount: cannot fork: %s"), strerror (errsv
));
1241 /* if child, or not forked, do the mounting */
1242 if (p
== 0 || p
== -1) {
1243 for (mc
= cp
->mec
; mc
; mc
= mc
->nxt
)
1244 status
|= mount_one (mc
->m
.mnt_fsname
, mc
->m
.mnt_dir
,
1245 mc
->m
.mnt_type
, mc
->m
.mnt_opts
,
1248 status
|= EX_SOMEOK
;
1254 /* wait for children, if any */
1255 while ((cp
= childhead
.nxt
) != NULL
) {
1256 childhead
.nxt
= cp
->nxt
;
1260 if(waitpid(cp
->pid
, &ret
, 0) == -1) {
1264 } else if (WIFEXITED(ret
))
1265 status
|= WEXITSTATUS(ret
);
1267 status
|= EX_SYSERR
;
1271 status
|= EX_SOMEOK
;
1275 extern char version
[];
1276 static struct option longopts
[] = {
1277 { "all", 0, 0, 'a' },
1278 { "fake", 0, 0, 'f' },
1279 { "fork", 0, 0, 'F' },
1280 { "help", 0, 0, 'h' },
1281 { "no-mtab", 0, 0, 'n' },
1282 { "read-only", 0, 0, 'r' },
1283 { "ro", 0, 0, 'r' },
1284 { "verbose", 0, 0, 'v' },
1285 { "version", 0, 0, 'V' },
1286 { "read-write", 0, 0, 'w' },
1287 { "rw", 0, 0, 'w' },
1288 { "options", 1, 0, 'o' },
1289 { "types", 1, 0, 't' },
1290 { "bind", 0, 0, 128 },
1291 { "replace", 0, 0, 129 },
1292 { "after", 0, 0, 130 },
1293 { "before", 0, 0, 131 },
1294 { "over", 0, 0, 132 },
1298 /* Keep the usage message at max 22 lines, each at most 70 chars long.
1299 The user should not need a pager to read it. */
1301 usage (FILE *fp
, int n
) {
1303 "Usage: mount -V : print version\n"
1304 " mount -h : print this help\n"
1305 " mount : list mounted filesystems\n"
1306 " mount -l : idem, including volume labels\n"
1307 "So far the informational part. Next the mounting.\n"
1308 "The command is `mount [-t fstype] something somewhere'.\n"
1309 "Details found in /etc/fstab may be omitted.\n"
1310 " mount -a : mount all stuff from /etc/fstab\n"
1311 " mount device : mount device at the known place\n"
1312 " mount directory : mount known device here\n"
1313 " mount -t type dev dir : ordinary mount command\n"
1314 "Note that one does not really mount a device, one mounts\n"
1315 "a filesystem (of the given type) found on the device.\n"
1316 "One can also mount an already visible directory tree elsewhere:\n"
1317 " mount --bind olddir newdir\n"
1318 "A device can be given by name, say /dev/hda1 or /dev/cdrom,\n"
1319 "or by label, using -L label or by uuid, using -U uuid .\n"
1320 "Union or stack mounts are specified using one of\n"
1321 " --replace, --after, --before, --over\n"
1322 "Other options: [-nfFrsvw] [-o options].\n"
1323 "For many more details, say man 8 mount .\n"
1330 main (int argc
, char *argv
[]) {
1331 int c
, result
= 0, specseen
;
1332 char *options
= NULL
, *spec
, *node
;
1333 char *volumelabel
= NULL
;
1335 string_list types
= NULL
;
1336 struct mntentchn
*mc
;
1339 setlocale(LC_ALL
, "");
1340 bindtextdomain(PACKAGE
, LOCALEDIR
);
1341 textdomain(PACKAGE
);
1343 /* People report that a mount called from init without console
1344 writes error messages to /etc/mtab
1345 Let us try to avoid getting fd's 0,1,2 */
1346 while((fd
= open("/dev/null", O_RDWR
)) == 0 || fd
== 1 || fd
== 2) ;
1350 #ifdef DO_PS_FIDDLING
1351 initproctitle(argc
, argv
);
1354 while ((c
= getopt_long (argc
, argv
, "afFhlL:no:rsU:vVwt:",
1355 longopts
, NULL
)) != EOF
) {
1357 case 'a': /* mount everything in fstab */
1360 case 'f': /* fake: don't actually call mount(2) */
1366 case 'h': /* help */
1370 list_with_volumelabel
= 1;
1373 volumelabel
= optarg
;
1375 case 'n': /* do not write /etc/mtab */
1378 case 'o': /* specify mount options */
1380 options
= xstrconcat3(options
, ",", optarg
);
1382 options
= xstrdup(optarg
);
1384 case 'r': /* mount readonly */
1388 case 's': /* allow sloppy mount options */
1391 case 't': /* specify file system types */
1392 types
= parse_list (optarg
);
1397 case 'v': /* be chatty - more so if repeated */
1400 case 'V': /* version */
1401 printf ("mount: %s\n", version
);
1403 case 'w': /* mount read/write */
1410 case 128: /* bind */
1413 case 129: /* replace */
1414 mounttype
= MS_REPLACE
;
1416 case 130: /* after */
1417 mounttype
= MS_AFTER
;
1419 case 131: /* before */
1420 mounttype
= MS_BEFORE
;
1422 case 132: /* over */
1423 mounttype
= MS_OVER
;
1428 usage (stderr
, EX_USAGE
);
1435 specseen
= (uuid
|| volumelabel
) ? 1 : 0; /* yes, .. i know */
1437 if (argc
+specseen
== 0 && !all
) {
1438 if (options
|| mounttype
|| bind
)
1439 usage (stderr
, EX_USAGE
);
1440 return print_all (types
);
1443 if (getuid () != geteuid ()) {
1445 if (types
|| options
|| readwrite
|| nomtab
|| all
|| fake
||
1446 bind
|| mounttype
|| (argc
+ specseen
) != 1)
1447 die (EX_USAGE
, _("mount: only root can do that"));
1450 if (!nomtab
&& mtab_does_not_exist()) {
1452 printf(_("mount: no %s found - creating it..\n"),
1459 spec
= get_spec_by_uuid(uuid
);
1461 spec
= get_spec_by_volume_label(volumelabel
);
1463 die (EX_USAGE
, _("mount: no such partition found"));
1465 printf(_("mount: mounting %s\n"), spec
);
1467 spec
= NULL
; /* just for gcc */
1469 switch (argc
+specseen
) {
1472 result
= mount_all (types
, options
);
1473 if (result
== 0 && verbose
)
1474 error(_("not mounted anything"));
1478 /* mount [-nfrvw] [-o options] special | node */
1480 usage (stderr
, EX_USAGE
);
1482 /* We know the device. Where shall we mount it? */
1483 mc
= (uuid
? getfsuuidspec (uuid
)
1484 : getfsvolspec (volumelabel
));
1486 mc
= getfsspec (spec
);
1489 _("mount: cannot find %s in %s"),
1491 mc
->m
.mnt_fsname
= spec
;
1493 /* Try to find the other pathname in fstab. */
1494 spec
= canonicalize (*argv
);
1495 if ((mc
= getfsspec (spec
)) == NULL
&&
1496 (mc
= getfsfile (spec
)) == NULL
&&
1497 /* Try noncanonical name in fstab
1498 perhaps /dev/cdrom or /dos is a symlink */
1499 (mc
= getfsspec (*argv
)) == NULL
&&
1500 (mc
= getfsfile (*argv
)) == NULL
&&
1501 /* Try mtab - maybe this was a remount */
1502 (mc
= getmntfile (spec
)) == NULL
)
1504 _("mount: can't find %s in %s or %s"),
1505 spec
, _PATH_FSTAB
, MOUNTED
);
1506 /* Earlier mtab was tried first, but this would
1507 sometimes try the wrong mount in case mtab had
1508 the root device entry wrong. */
1511 result
= mount_one (xstrdup (mc
->m
.mnt_fsname
),
1512 xstrdup (mc
->m
.mnt_dir
),
1513 xstrdup (mc
->m
.mnt_type
),
1514 mc
->m
.mnt_opts
, options
, 0, 0);
1518 /* mount [-nfrvw] [-t vfstype] [-o options] special node */
1520 /* we have spec already */
1527 result
= mount_one (spec
, node
, NULL
, NULL
,
1529 else if (cdr (types
) == NULL
)
1530 result
= mount_one (spec
, node
, car (types
), NULL
,
1533 usage (stderr
, EX_USAGE
);
1537 usage (stderr
, EX_USAGE
);
1540 if (result
== EX_SOMEOK
)