404 lines
11 KiB
C
404 lines
11 KiB
C
/*
|
|
* 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
|
|
* it was previously.
|
|
*
|
|
* Wed Feb 8 09:23:18 1995: Mike Grupenhoff <kashmir@umiacs.UMD.EDU> added
|
|
* a probe of the superblock for the type before /proc/filesystems is
|
|
* checked.
|
|
*
|
|
* Fri Apr 5 01:13:33 1996: quinlan@bucknell.edu, fixed up iso9660 autodetect
|
|
*
|
|
* Wed Nov 11 11:33:55 1998: K.Garloff@ping.de, try /etc/filesystems before
|
|
* /proc/filesystems
|
|
* [This was mainly in order to specify vfat before fat; these days we often
|
|
* detect *fat and then assume vfat, so perhaps /etc/filesystems isnt
|
|
* so useful anymore.]
|
|
*
|
|
* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
|
|
* - added Native Language Support
|
|
*
|
|
* Fri Dec 1 23:31:00 2000: Sepp Wijnands <mrrazz@garbage-coderz.net>
|
|
* added probes for cramfs, hfs, hpfs and adfs.
|
|
*
|
|
* aeb - many changes.
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include "linux_fs.h"
|
|
#include "mount_guess_fstype.h"
|
|
#include "sundries.h" /* for xstrdup */
|
|
#include "nls.h"
|
|
|
|
#define ETC_FILESYSTEMS "/etc/filesystems"
|
|
#define PROC_FILESYSTEMS "/proc/filesystems"
|
|
|
|
#define SIZE(a) (sizeof(a)/sizeof(a[0]))
|
|
|
|
/* Most file system types can be recognized by a `magic' number
|
|
in the superblock. Note that the order of the tests is
|
|
significant: by coincidence a filesystem can have the
|
|
magic numbers for several file system types simultaneously.
|
|
For example, the romfs magic lives in the 1st sector;
|
|
xiafs does not touch the 1st sector and has its magic in
|
|
the 2nd sector; ext2 does not touch the first two sectors. */
|
|
|
|
static inline unsigned short
|
|
swapped(unsigned short a) {
|
|
return (a>>8) | (a<<8);
|
|
}
|
|
|
|
/*
|
|
char *guess_fstype_from_superblock(const char *device);
|
|
|
|
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 iso9660, romfs, qnx4, udf, swap - aeb
|
|
Added a test for high sierra (iso9660) - quinlan@bucknell.edu
|
|
Corrected the test for xiafs - aeb
|
|
Added ufs from a patch by jj. But maybe there are several types of ufs?
|
|
Added ntfs from a patch by Richard Russon.
|
|
Added a very weak heuristic for vfat - aeb
|
|
Added xfs - 2000-03-21 Martin K. Petersen <mkp@linuxcare.com>
|
|
Added cramfs, hfs, hpfs, adfs - Sepp Wijnands <mrrazz@garbage-coderz.net>
|
|
*/
|
|
static char
|
|
*magic_known[] = {
|
|
"adfs", "bfs", "cramfs", "ext", "ext2",
|
|
"hfs", "hpfs", "iso9660", "minix", "ntfs",
|
|
"qnx4", "romfs", "swap", "udf", "ufs",
|
|
"xfs", "xiafs"
|
|
};
|
|
|
|
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;
|
|
}
|
|
|
|
/* udf magic - I find that trying to mount garbage as an udf fs
|
|
causes a very large kernel delay, almost killing the machine.
|
|
So, we do not try udf unless there is positive evidence that it
|
|
might work. Try iso9660 first, it is much more likely.
|
|
Strings below taken from ECMA 167. */
|
|
static char
|
|
*udf_magic[] = { "BEA01", "BOOT2", "CD001", "CDW02", "NSR02",
|
|
"NSR03", "TEA01" };
|
|
|
|
static int
|
|
may_be_udf(const char *id) {
|
|
char **m;
|
|
|
|
for (m = udf_magic; m - udf_magic < SIZE(udf_magic); m++)
|
|
if (!strncmp(*m, id, 5))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
may_be_swap(const char *s) {
|
|
return (strncmp(s-10, "SWAP-SPACE", 10) == 0 ||
|
|
strncmp(s-10, "SWAPSPACE2", 10) == 0);
|
|
}
|
|
|
|
/* rather weak necessary condition */
|
|
static int
|
|
may_be_adfs(const u_char *s) {
|
|
u_char *p;
|
|
int sum;
|
|
|
|
p = (u_char *) s + 511;
|
|
sum = 0;
|
|
while(--p != s)
|
|
sum = (sum >> 8) + (sum & 0xff) + *p;
|
|
|
|
return (sum == p[511]);
|
|
}
|
|
|
|
static char *
|
|
fstype(const char *device) {
|
|
int fd;
|
|
char *type = NULL;
|
|
union {
|
|
struct minix_super_block ms;
|
|
struct ext_super_block es;
|
|
struct ext2_super_block e2s;
|
|
} sb;
|
|
union {
|
|
struct xiafs_super_block xiasb;
|
|
char romfs_magic[8];
|
|
char qnx4fs_magic[10]; /* ignore first 4 bytes */
|
|
long bfs_magic;
|
|
struct ntfs_super_block ntfssb;
|
|
struct fat_super_block fatsb;
|
|
struct xfs_super_block xfsb;
|
|
struct cramfs_super_block cramfssb;
|
|
} xsb;
|
|
struct ufs_super_block ufssb;
|
|
union {
|
|
struct iso_volume_descriptor iso;
|
|
struct hs_volume_descriptor hs;
|
|
} isosb;
|
|
struct hfs_super_block hfssb;
|
|
struct hpfs_super_block hpfssb;
|
|
struct adfs_super_block adfssb;
|
|
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) || !S_ISBLK(statbuf.st_mode))
|
|
return 0;
|
|
|
|
fd = open(device, O_RDONLY);
|
|
if (fd < 0)
|
|
return 0;
|
|
|
|
if (lseek(fd, 1024, SEEK_SET) != 1024
|
|
|| read(fd, (char *) &sb, sizeof(sb)) != sizeof(sb))
|
|
goto io_error;
|
|
|
|
if (ext2magic(sb.e2s) == EXT2_SUPER_MAGIC
|
|
|| ext2magic(sb.e2s) == EXT2_PRE_02B_MAGIC
|
|
|| ext2magic(sb.e2s) == swapped(EXT2_SUPER_MAGIC))
|
|
type = "ext2";
|
|
|
|
else if (minixmagic(sb.ms) == MINIX_SUPER_MAGIC
|
|
|| minixmagic(sb.ms) == MINIX_SUPER_MAGIC2
|
|
|| minixmagic(sb.ms) == swapped(MINIX_SUPER_MAGIC2))
|
|
type = "minix";
|
|
|
|
else if (extmagic(sb.es) == EXT_SUPER_MAGIC)
|
|
type = "ext";
|
|
|
|
if (!type) {
|
|
if (lseek(fd, 0, SEEK_SET) != 0
|
|
|| read(fd, (char *) &xsb, sizeof(xsb)) != sizeof(xsb))
|
|
goto io_error;
|
|
|
|
if (xiafsmagic(xsb.xiasb) == _XIAFS_SUPER_MAGIC)
|
|
type = "xiafs";
|
|
else if(!strncmp(xsb.romfs_magic, "-rom1fs-", 8))
|
|
type = "romfs";
|
|
else if(!strncmp(xsb.xfsb.s_magic, XFS_SUPER_MAGIC, 4) ||
|
|
!strncmp(xsb.xfsb.s_magic, XFS_SUPER_MAGIC2, 4))
|
|
type = "xfs";
|
|
else if(!strncmp(xsb.qnx4fs_magic+4, "QNX4FS", 6))
|
|
type = "qnx4fs";
|
|
else if(xsb.bfs_magic == 0x1badface)
|
|
type = "bfs";
|
|
else if(!strncmp(xsb.ntfssb.s_magic, NTFS_SUPER_MAGIC,
|
|
sizeof(xsb.ntfssb.s_magic)))
|
|
type = "ntfs";
|
|
else if(cramfsmagic(xsb.cramfssb) == CRAMFS_SUPER_MAGIC)
|
|
type = "cramfs";
|
|
else if ((!strncmp(xsb.fatsb.s_os, "MSDOS", 5) ||
|
|
!strncmp(xsb.fatsb.s_os, "MSWIN", 5) ||
|
|
!strncmp(xsb.fatsb.s_os, "MTOOL", 5) ||
|
|
!strncmp(xsb.fatsb.s_os, "mkdosfs", 7) ||
|
|
!strncmp(xsb.fatsb.s_os, "kmkdosfs", 8))
|
|
&& (!strncmp(xsb.fatsb.s_fs, "FAT12 ", 8) ||
|
|
!strncmp(xsb.fatsb.s_fs, "FAT16 ", 8) ||
|
|
!strncmp(xsb.fatsb.s_fs2, "FAT32 ", 8)))
|
|
type = "vfat"; /* only guessing - might as well be fat or umsdos */
|
|
}
|
|
|
|
if (!type) {
|
|
if (lseek(fd, 8192, SEEK_SET) != 8192
|
|
|| read(fd, (char *) &ufssb, sizeof(ufssb)) != sizeof(ufssb))
|
|
goto io_error;
|
|
|
|
if (ufsmagic(ufssb) == UFS_SUPER_MAGIC) /* also test swapped version? */
|
|
type = "ufs";
|
|
}
|
|
|
|
if (!type) {
|
|
if (lseek(fd, 0x8000, SEEK_SET) != 0x8000
|
|
|| read(fd, (char *) &isosb, sizeof(isosb)) != sizeof(isosb))
|
|
goto io_error;
|
|
|
|
if(strncmp(isosb.iso.id, ISO_STANDARD_ID, sizeof(isosb.iso.id)) == 0
|
|
|| strncmp(isosb.hs.id, HS_STANDARD_ID, sizeof(isosb.hs.id)) == 0)
|
|
type = "iso9660";
|
|
else if (may_be_udf(isosb.iso.id))
|
|
type = "udf";
|
|
}
|
|
|
|
if (!type) {
|
|
if (lseek(fd, 0x400, SEEK_SET) != 0x400
|
|
|| read(fd, (char *) &hfssb, sizeof(hfssb)) != sizeof(hfssb))
|
|
goto io_error;
|
|
|
|
/* also check if block size is equal to 512 bytes,
|
|
since the hfs driver currently only has support
|
|
for block sizes of 512 bytes long, and to be
|
|
more accurate (sb magic is only a short int) */
|
|
if ((hfsmagic(hfssb) == HFS_SUPER_MAGIC &&
|
|
hfsblksize(hfssb) == 0x20000) ||
|
|
(swapped(hfsmagic(hfssb)) == HFS_SUPER_MAGIC &&
|
|
hfsblksize(hfssb) == 0x200))
|
|
type = "hfs";
|
|
}
|
|
|
|
if (!type) {
|
|
if (lseek(fd, 0x2000, SEEK_SET) != 0x2000
|
|
|| read(fd, (char *) &hpfssb, sizeof(hpfssb)) != sizeof(hpfssb))
|
|
goto io_error;
|
|
|
|
if (hpfsmagic(hpfssb) == HPFS_SUPER_MAGIC)
|
|
type = "hpfs";
|
|
}
|
|
|
|
if (!type) {
|
|
if (lseek(fd, 0xc00, SEEK_SET) != 0xc00
|
|
|| read(fd, (char *) &adfssb, sizeof(adfssb)) != sizeof(adfssb))
|
|
goto io_error;
|
|
|
|
/* only a weak test */
|
|
if (may_be_adfs((u_char *) &adfssb)
|
|
&& (adfsblksize(adfssb) >= 8 &&
|
|
adfsblksize(adfssb) <= 10))
|
|
type = "adfs";
|
|
}
|
|
|
|
if (!type) {
|
|
/* perhaps the user tries to mount the swap space
|
|
on a new disk; warn her before she does mke2fs on it */
|
|
int pagesize = getpagesize();
|
|
int rd;
|
|
char buf[32768];
|
|
|
|
rd = pagesize;
|
|
if (rd < 8192)
|
|
rd = 8192;
|
|
if (rd > sizeof(buf))
|
|
rd = sizeof(buf);
|
|
if (lseek(fd, 0, SEEK_SET) != 0
|
|
|| read(fd, buf, rd) != rd)
|
|
goto io_error;
|
|
if (may_be_swap(buf+pagesize) ||
|
|
may_be_swap(buf+4096) || may_be_swap(buf+8192))
|
|
type = "swap";
|
|
}
|
|
|
|
close (fd);
|
|
return(type);
|
|
|
|
io_error:
|
|
perror(device);
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
|
|
char *
|
|
guess_fstype_from_superblock(const char *spec) {
|
|
char *type = fstype(spec);
|
|
if (verbose) {
|
|
printf (_("mount: you didn't specify a filesystem type for %s\n"),
|
|
spec);
|
|
if (!type)
|
|
printf (_(" I will try all types mentioned in %s or %s\n"),
|
|
ETC_FILESYSTEMS, PROC_FILESYSTEMS);
|
|
else if (!strcmp(type, "swap"))
|
|
printf (_(" and it looks like this is swapspace\n"));
|
|
else
|
|
printf (_(" I will try type %s\n"), type);
|
|
}
|
|
return type;
|
|
}
|
|
|
|
static char *
|
|
procfsnext(FILE *procfs) {
|
|
char line[100];
|
|
char fsname[100];
|
|
|
|
while (fgets(line, sizeof(line), procfs)) {
|
|
if (sscanf (line, "nodev %[^\n]\n", fsname) == 1) continue;
|
|
if (sscanf (line, " %[^ \n]\n", fsname) != 1) continue;
|
|
return strdup(fsname);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Only use /proc/filesystems here, this is meant to test what
|
|
the kernel knows about, so /etc/filesystems is irrelevant.
|
|
Return: 1: yes, 0: no, -1: cannot open procfs */
|
|
int
|
|
is_in_procfs(const char *type) {
|
|
FILE *procfs;
|
|
char *fsname;
|
|
int ret = -1;
|
|
|
|
procfs = fopen(PROC_FILESYSTEMS, "r");
|
|
if (procfs) {
|
|
ret = 0;
|
|
while ((fsname = procfsnext(procfs)) != NULL)
|
|
if (!strcmp(fsname, type)) {
|
|
ret = 1;
|
|
break;
|
|
}
|
|
fclose(procfs);
|
|
procfs = NULL;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* return: 0: OK, -1: error in errno, 1: type not found */
|
|
/* when 1 is returned, *type is NULL */
|
|
int
|
|
procfsloop(int (*mount_fn)(struct mountargs *), struct mountargs *args,
|
|
char **type) {
|
|
FILE *procfs;
|
|
char *fsname;
|
|
int ret = 1;
|
|
int errsv = 0;
|
|
|
|
*type = NULL;
|
|
|
|
procfs = fopen(ETC_FILESYSTEMS, "r");
|
|
if (!procfs) {
|
|
procfs = fopen(PROC_FILESYSTEMS, "r");
|
|
if (!procfs)
|
|
return 1;
|
|
}
|
|
while ((fsname = procfsnext(procfs)) != NULL) {
|
|
if (tested (fsname))
|
|
continue;
|
|
args->type = fsname;
|
|
if (verbose) {
|
|
printf(_("Trying %s\n"), fsname);
|
|
fflush(stdout);
|
|
}
|
|
if ((*mount_fn) (args) == 0) {
|
|
*type = fsname;
|
|
ret = 0;
|
|
break;
|
|
} else if (errno != EINVAL && is_in_procfs(fsname) == 1) {
|
|
*type = "guess";
|
|
ret = -1;
|
|
errsv = errno;
|
|
break;
|
|
}
|
|
}
|
|
fclose(procfs);
|
|
errno = errsv;
|
|
return ret;
|
|
}
|