diff options
Diffstat (limited to 'mount/mount.c')
-rw-r--r-- | mount/mount.c | 281 |
1 files changed, 205 insertions, 76 deletions
diff --git a/mount/mount.c b/mount/mount.c index b6ffbcd67..028848ac5 100644 --- a/mount/mount.c +++ b/mount/mount.c @@ -2,7 +2,7 @@ * A mount(8) for Linux 0.99. * mount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp * - * Thu Jul 14 07:32:40 1994: faith@cs.unc.edu added changed from Adam + * Thu Jul 14 07:32:40 1994: faith@cs.unc.edu added changes from Adam * J. Richter (adam@adam.yggdrasil.com) so that /proc/filesystems is used * if no -t option is given. I modified his patches so that, if * /proc/filesystems is not available, the behavior of mount is the same as @@ -20,6 +20,8 @@ * checked. * * Wed Feb 8 12:27:00 1995: Andries.Brouwer@cwi.nl fixed up error messages. + * Sat Jun 3 20:44:38 1995: Patches from Andries.Brouwer@cwi.nl applied. + * Tue Sep 26 22:38:20 1995: aeb@cwi.nl, many changes * */ @@ -33,6 +35,9 @@ #include <sys/stat.h> #include <unistd.h> +#define PROC_FILESYSTEMS "/proc/filesystems" +#define SIZE(a) (sizeof(a)/sizeof(a[0])) + int del_loop (const char *); /* True for fake mount (-f). */ @@ -100,14 +105,20 @@ const struct opt_map opt_map[] = { "sub", 1, MS_NOSUB }, /* allow submounts */ { "nosub", 0, MS_NOSUB }, /* don't allow submounts */ #endif +#ifdef MS_SILENT + { "quiet", 0, MS_SILENT }, /* be quiet */ + { "loud", 1, MS_SILENT }, /* print out messages. */ +#endif { NULL, 0, 0 } }; +int mount_quiet=0; /* Report on a single mount. */ static void print_one (const struct mntent *mnt) { + if (mount_quiet) return; printf ("%s on %s", mnt->mnt_fsname, mnt->mnt_dir); if ((mnt->mnt_type != NULL) && *mnt->mnt_type != '\0') printf (" type %s", mnt->mnt_type); @@ -151,6 +162,12 @@ parse_opt (const char *opt, int *mask, char *extra_opts) *mask |= om->mask; if (om->mask == MS_USER) *mask |= MS_SECURE; +#ifdef MS_SILENT + if (om->mask == MS_SILENT && om->inv) { + mount_quiet = 1; + verbose = 0; + } +#endif return; } if (*extra_opts) @@ -218,97 +235,192 @@ fix_opts_string (int flags, char *extra_opts) /* char *fstype(const char *device); - probes the device and attempts to determine the type of filesystem + Probes the device and attempts to determine the type of filesystem contained within. Original routine by <jmorriso@bogomips.ww.ubc.ca>; made into a function for mount(8) by Mike Grupenhoff <kashmir@umiacs.umd.edu>. + Read the superblock only once - aeb + Added a test for iso9660 - aeb - Currently supports: minix, ext, ext2, xia + Currently supports: minix, ext, ext2, xiafs, iso9660 */ +char *magic_known[] = { "minix", "ext", "ext2", "xiafs", "iso9660" }; + +static int +tested(const char *device) { + char **m; + + for (m = magic_known; m - magic_known < SIZE(magic_known); m++) + if (!strcmp(*m, device)) + return 1; + return 0; +} static char * fstype(const char *device) { int fd; - - /* MINIX */ - struct minix_super_block ms; - /* extended fs */ - struct ext_super_block es; - /* 2nd extended fs */ - struct ext2_super_block e2s; - /* xia fs */ - struct xiafs_super_block xfs; + char ifs_magic[8]; + union { + struct minix_super_block ms; + struct ext_super_block es; + struct ext2_super_block e2s; + struct xiafs_super_block xfs; + } sb; + struct stat statbuf; + + /* opening and reading an arbitrary unknown path can have + undesired side effects - first check that `device' refers + to a block device */ + if (stat (device, &statbuf)) + error("mount: %s does not exist", device); + if (!S_ISBLK(statbuf.st_mode)) + error("mount: %s is not a block device", device); fd = open(device, O_RDONLY); - if (fd < 0) { + if (fd < 0 + || lseek(fd, BLOCK_SIZE, SEEK_SET) < 0 + || read(fd, (char *) &sb, sizeof(sb)) < 0) { perror(device); return 0; } - lseek(fd, BLOCK_SIZE, SEEK_SET); - read(fd, (char *) &ms, sizeof(ms)); - if (ms.s_magic == MINIX_SUPER_MAGIC || ms.s_magic == MINIX_SUPER_MAGIC2) { - close(fd); + + if (sb.ms.s_magic == MINIX_SUPER_MAGIC + || sb.ms.s_magic == MINIX_SUPER_MAGIC2) { + close (fd); return("minix"); } - lseek(fd, BLOCK_SIZE, SEEK_SET); - read(fd, (char *) &es, sizeof(es)); - if (es.s_magic == EXT_SUPER_MAGIC) { - close(fd); + if (sb.es.s_magic == EXT_SUPER_MAGIC) { + close (fd); return("ext"); } - lseek(fd, BLOCK_SIZE, SEEK_SET); - read(fd, (char *) &e2s, sizeof(e2s)); - if (e2s.s_magic == EXT2_SUPER_MAGIC || e2s.s_magic == EXT2_PRE_02B_MAGIC) { - close(fd); +#ifndef EXT2_PRE_02B_MAGIC +#define EXT2_PRE_02B_MAGIC 0xEF51 +#endif + if (sb.e2s.s_magic == EXT2_SUPER_MAGIC + || sb.e2s.s_magic == EXT2_PRE_02B_MAGIC) { + close (fd); return("ext2"); } - lseek(fd, 0, SEEK_SET); - read(fd, (char *) &xfs, sizeof(xfs)); - if (xfs.s_magic == _XIAFS_SUPER_MAGIC) { - close(fd); + if (sb.xfs.s_magic == _XIAFS_SUPER_MAGIC) { + close (fd); return("xiafs"); } - close(fd); + if (lseek (fd, 0100000, SEEK_SET) != -1 + && read (fd, ifs_magic, 8) == 8 + && !strncmp(ifs_magic, "\001CD001\001", 8)) { /* ECMA 119 */ + close (fd); + return("iso9660"); + } + close (fd); return(0); +} +FILE *procfs; + +static void +procclose(void) { + if (procfs) + fclose (procfs); + procfs = 0; +} + +static int +procopen(void) { + return ((procfs = fopen(PROC_FILESYSTEMS, "r")) != NULL); +} + +static char * +procnext(void) { + char line[100]; + static char fsname[50]; + + while (fgets(line, sizeof(line), procfs)) { + if (sscanf (line, "nodev %[^\n]\n", fsname) == 1) continue; + if (sscanf (line, " %[^ \n]\n", fsname) != 1) continue; + return fsname; + } + return 0; } +static int +is_in_proc(char *type) { + char *fsname; + + if (procopen()) { + while ((fsname = procnext()) != NULL) + if (!strcmp(fsname, type)) + return 1; + } + return 0; +} + +static int +already (char *spec, char *node) { + struct mntent *me; + int ret = 1; + + if ((me = getmntfile(node)) != NULL) + error ("mount: according to mtab, %s is already mounted on %s", + me->mnt_fsname, node); + else if ((me = getmntfile(spec)) != NULL) + error ("mount: according to mtab, %s is mounted on %s", + spec, me->mnt_dir); + else + ret = 0; + return ret; +} /* Mount a single file system. Return status, so don't exit on non-fatal errors. */ static int try_mount5 (char *spec, char *node, char **type, int flags, char *mount_opts) { - FILE *procfs_file; - char line[100]; - char fsname[50]; + char *fsname; - if (*type) return mount5 (spec, node, *type, flags & ~MS_NOSYS, mount_opts); - if (( procfs_file = fopen("/proc/filesystems", "r")) == NULL) { - /* If /proc/filesystems is not available, - preserve the old behavior of mount. */ - return mount5 (spec, - node, - FSTYPE_DEFAULT, - flags & ~MS_NOSYS, mount_opts); + if (strcasecmp (*type, "auto") == 0) + *type = NULL; + + if (!*type) { + *type = fstype(spec); + if (!*type && !procopen()) + *type = FSTYPE_DEFAULT; + if (verbose) { + printf ("mount: you didn't specify a filesystem type for %s\n", + spec); + if (*type) + printf (" I will try type %s\n", *type); + else + printf (" I will try all types mentioned in %s\n", + PROC_FILESYSTEMS); + } } - while (fgets(line, sizeof(line), procfs_file)) { - if (sscanf (line, "nodev %[^\n]\n", fsname) == 1) continue; - if (sscanf (line, " %[^ \n]\n", fsname) != 1) continue; + + if (*type) + return mount5 (spec, node, *type, flags & ~MS_NOSYS, mount_opts); + + while ((fsname = procnext()) != NULL) { + if (tested (fsname)) + continue; if (mount5 (spec, node, fsname, flags & ~MS_NOSYS, mount_opts) == 0) { - *type=xstrdup(fsname); - fclose(procfs_file); - return 0; + *type = xstrdup(fsname); + procclose(); + return 0; + } else if (errno != EINVAL) { + *type = "guess"; + procclose(); + return 1; } } - fclose(procfs_file); + procclose(); + *type = NULL; + return -1; } @@ -321,7 +433,7 @@ mount_one (char *spec, char *node, char *type, char *opts, int freq, int pass) int flags; char *extra_opts; char *mount_opts; - int anti_recurse = 0; + static int added_ro = 0; int loop=0; if (type == NULL) @@ -333,8 +445,12 @@ mount_one (char *spec, char *node, char *type, char *opts, int freq, int pass) parse_opts (xstrdup (opts), &flags, &extra_opts); /* root may allow certain types of mounts by ordinary users */ - if (suid && !(flags & MS_USER)) - die (3, "mount: only root can mount %s on %s", spec, node); + if (suid && !(flags & MS_USER)) { + if (already (spec, node)) + die (3, "mount failed"); + else + die (3, "mount: only root can mount %s on %s", spec, node); + } /* quietly succeed for fstab entries that don't get mounted automatically */ if (all && (flags & MS_NOAUTO)) @@ -360,12 +476,9 @@ mount_one (char *spec, char *node, char *type, char *opts, int freq, int pass) if (nfsmount (spec, node, &flags, &extra_opts, &mount_opts) != 0) return 1; #else - die (1, "mount: this version doesn't support the type `nfs'"); + die (1, "mount: this version was compiled without support for the type `nfs'"); #endif - if (!type && !(type = fstype(spec))) - return 1; - block_signals (SIG_BLOCK); if (fake @@ -376,7 +489,7 @@ mount_one (char *spec, char *node, char *type, char *opts, int freq, int pass) { mnt.mnt_fsname = canonicalize (spec); mnt.mnt_dir = canonicalize (node); - mnt.mnt_type = loop?"loop":type; + mnt.mnt_type = loop ? "loop" : type; mnt.mnt_opts = fix_opts_string (flags & ~MS_NOMTAB, loop?opts:extra_opts); mnt.mnt_freq = freq; @@ -411,6 +524,10 @@ mount_one (char *spec, char *node, char *type, char *opts, int freq, int pass) block_signals (SIG_UNBLOCK); /* Mount failed, complain, but don't die. */ + + if (type == 0) + error ("mount: you must specify the filesystem type"); + else switch (mnt_err) { case EPERM: @@ -421,11 +538,15 @@ mount_one (char *spec, char *node, char *type, char *opts, int freq, int pass) break; case EBUSY: error ("mount: %s already mounted or %s busy", spec, node); + already (spec, node); break; case ENOENT: { struct stat statbuf; - if (stat (node, &statbuf)) + if (lstat (node, &statbuf)) error ("mount: mount point %s does not exist", node); + else if (stat (node, &statbuf)) + error ("mount: mount point %s is a symbolic link to nowhere", + node); else if (stat (spec, &statbuf)) error ("mount: special device %s does not exist", spec); else { @@ -433,7 +554,7 @@ mount_one (char *spec, char *node, char *type, char *opts, int freq, int pass) perror("mount"); } break; - } + } case ENOTDIR: error ("mount: mount point %s is not a directory", node); break; case EINVAL: @@ -443,31 +564,37 @@ mount_one (char *spec, char *node, char *type, char *opts, int freq, int pass) case EIO: error ("mount: %s: can't read superblock", spec); break; case ENODEV: - error ("mount: fs type %s not supported by kernel", type); break; + if (is_in_proc(type)) + error("mount: %s has wrong major or minor number", spec); + else if (procfs) + error ("mount: fs type %s not supported by kernel", type); + else + error ("mount: %s has wrong device number or fs type %s not supported", + spec, type); + break; case ENOTBLK: error ("mount: %s is not a block device", spec); break; case ENXIO: error ("mount: %s is not a valid block device", spec); break; case EACCES: /* pre-linux 1.1.38 */ case EROFS: /* linux 1.1.38 and later */ - if (anti_recurse) - { - error ("mount: block device %s is not permitted on its filesystem", spec); + if (added_ro) { + error ("mount: block device %s is not permitted on its filesystem", + spec); break; - } - else - { - anti_recurse++; - if (opts) - { - opts = realloc(xstrdup(opts), strlen(opts)+3); + } else { + added_ro = 1; + if (opts) { + opts = realloc(xstrdup(opts), strlen(opts)+4); strcat(opts, ",ro"); - } - else - opts = "ro"; - error ("mount: block device %s is write-protected, mounting read-only", spec); - return mount_one (spec, node, type, opts, freq, pass); - } + } else + opts = "ro"; + if (type && !strcmp(type, "guess")) + type = 0; + error ("mount: block device %s is write-protected, " + "mounting read-only", spec); + return mount_one (spec, node, type, opts, freq, pass); + } break; default: error ("mount: %s", strerror (mnt_err)); break; @@ -514,6 +641,7 @@ mount_all (string_list types) } status = 0; + if (!setfsent()) return 1; while ((fstab = getfsent ()) != NULL) if (matching_type (fstab->mnt_type, types) && !streq (fstab->mnt_dir, "/") @@ -592,6 +720,7 @@ static void usage (FILE *fp, int n) { fprintf (fp, "%s", usage_string); + unlock_mtab(); exit (n); } @@ -629,7 +758,7 @@ main (int argc, char *argv[]) ++verbose; break; case 'V': /* version */ - printf ("%s\n", version); + printf ("mount: %s\n", version); exit (0); case 'w': /* mount read/write */ ++readwrite; |