]> git.ipfire.org Git - thirdparty/util-linux.git/blob - mount/mount_guess_fstype.c
Imported from util-linux-2.10s tarball.
[thirdparty/util-linux.git] / mount / mount_guess_fstype.c
1 /*
2 * Thu Jul 14 07:32:40 1994: faith@cs.unc.edu added changes from Adam
3 * J. Richter (adam@adam.yggdrasil.com) so that /proc/filesystems is used
4 * if no -t option is given. I modified his patches so that, if
5 * /proc/filesystems is not available, the behavior of mount is the same as
6 * it was previously.
7 *
8 * Wed Feb 8 09:23:18 1995: Mike Grupenhoff <kashmir@umiacs.UMD.EDU> added
9 * a probe of the superblock for the type before /proc/filesystems is
10 * checked.
11 *
12 * Fri Apr 5 01:13:33 1996: quinlan@bucknell.edu, fixed up iso9660 autodetect
13 *
14 * Wed Nov 11 11:33:55 1998: K.Garloff@ping.de, try /etc/filesystems before
15 * /proc/filesystems
16 * [This was mainly in order to specify vfat before fat; these days we often
17 * detect *fat and then assume vfat, so perhaps /etc/filesystems isnt
18 * so useful anymore.]
19 *
20 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
21 * - added Native Language Support
22 *
23 * Fri Dec 1 23:31:00 2000: Sepp Wijnands <mrrazz@garbage-coderz.net>
24 * added probes for cramfs, hfs, hpfs and adfs.
25 *
26 * aeb - many changes.
27 *
28 */
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <unistd.h>
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include "linux_fs.h"
38 #include "mount_guess_fstype.h"
39 #include "sundries.h" /* for xstrdup */
40 #include "nls.h"
41
42 #define ETC_FILESYSTEMS "/etc/filesystems"
43 #define PROC_FILESYSTEMS "/proc/filesystems"
44
45 #define SIZE(a) (sizeof(a)/sizeof(a[0]))
46
47 /* Most file system types can be recognized by a `magic' number
48 in the superblock. Note that the order of the tests is
49 significant: by coincidence a filesystem can have the
50 magic numbers for several file system types simultaneously.
51 For example, the romfs magic lives in the 1st sector;
52 xiafs does not touch the 1st sector and has its magic in
53 the 2nd sector; ext2 does not touch the first two sectors. */
54
55 static inline unsigned short
56 swapped(unsigned short a) {
57 return (a>>8) | (a<<8);
58 }
59
60 /*
61 char *guess_fstype_from_superblock(const char *device);
62
63 Probes the device and attempts to determine the type of filesystem
64 contained within.
65
66 Original routine by <jmorriso@bogomips.ww.ubc.ca>; made into a function
67 for mount(8) by Mike Grupenhoff <kashmir@umiacs.umd.edu>.
68 Read the superblock only once - aeb
69 Added iso9660, romfs, qnx4, udf, swap - aeb
70 Added a test for high sierra (iso9660) - quinlan@bucknell.edu
71 Corrected the test for xiafs - aeb
72 Added ufs from a patch by jj. But maybe there are several types of ufs?
73 Added ntfs from a patch by Richard Russon.
74 Added a very weak heuristic for vfat - aeb
75 Added xfs - 2000-03-21 Martin K. Petersen <mkp@linuxcare.com>
76 Added cramfs, hfs, hpfs, adfs - Sepp Wijnands <mrrazz@garbage-coderz.net>
77 */
78 static char
79 *magic_known[] = {
80 "adfs", "bfs", "cramfs", "ext", "ext2",
81 "hfs", "hpfs", "iso9660", "minix", "ntfs",
82 "qnx4", "romfs", "swap", "udf", "ufs",
83 "xfs", "xiafs"
84 };
85
86 static int
87 tested(const char *device) {
88 char **m;
89
90 for (m = magic_known; m - magic_known < SIZE(magic_known); m++)
91 if (!strcmp(*m, device))
92 return 1;
93 return 0;
94 }
95
96 /* udf magic - I find that trying to mount garbage as an udf fs
97 causes a very large kernel delay, almost killing the machine.
98 So, we do not try udf unless there is positive evidence that it
99 might work. Try iso9660 first, it is much more likely.
100 Strings below taken from ECMA 167. */
101 static char
102 *udf_magic[] = { "BEA01", "BOOT2", "CD001", "CDW02", "NSR02",
103 "NSR03", "TEA01" };
104
105 static int
106 may_be_udf(const char *id) {
107 char **m;
108
109 for (m = udf_magic; m - udf_magic < SIZE(udf_magic); m++)
110 if (!strncmp(*m, id, 5))
111 return 1;
112 return 0;
113 }
114
115 static int
116 may_be_swap(const char *s) {
117 return (strncmp(s-10, "SWAP-SPACE", 10) == 0 ||
118 strncmp(s-10, "SWAPSPACE2", 10) == 0);
119 }
120
121 /* rather weak necessary condition */
122 static int
123 may_be_adfs(const u_char *s) {
124 u_char *p;
125 int sum;
126
127 p = (u_char *) s + 511;
128 sum = 0;
129 while(--p != s)
130 sum = (sum >> 8) + (sum & 0xff) + *p;
131
132 return (sum == p[511]);
133 }
134
135 static char *
136 fstype(const char *device) {
137 int fd;
138 char *type = NULL;
139 union {
140 struct minix_super_block ms;
141 struct ext_super_block es;
142 struct ext2_super_block e2s;
143 } sb;
144 union {
145 struct xiafs_super_block xiasb;
146 char romfs_magic[8];
147 char qnx4fs_magic[10]; /* ignore first 4 bytes */
148 long bfs_magic;
149 struct ntfs_super_block ntfssb;
150 struct fat_super_block fatsb;
151 struct xfs_super_block xfsb;
152 struct cramfs_super_block cramfssb;
153 } xsb;
154 struct ufs_super_block ufssb;
155 union {
156 struct iso_volume_descriptor iso;
157 struct hs_volume_descriptor hs;
158 } isosb;
159 struct hfs_super_block hfssb;
160 struct hpfs_super_block hpfssb;
161 struct adfs_super_block adfssb;
162 struct stat statbuf;
163
164 /* opening and reading an arbitrary unknown path can have
165 undesired side effects - first check that `device' refers
166 to a block device */
167 if (stat (device, &statbuf) || !S_ISBLK(statbuf.st_mode))
168 return 0;
169
170 fd = open(device, O_RDONLY);
171 if (fd < 0)
172 return 0;
173
174 if (lseek(fd, 1024, SEEK_SET) != 1024
175 || read(fd, (char *) &sb, sizeof(sb)) != sizeof(sb))
176 goto io_error;
177
178 if (ext2magic(sb.e2s) == EXT2_SUPER_MAGIC
179 || ext2magic(sb.e2s) == EXT2_PRE_02B_MAGIC
180 || ext2magic(sb.e2s) == swapped(EXT2_SUPER_MAGIC))
181 type = "ext2";
182
183 else if (minixmagic(sb.ms) == MINIX_SUPER_MAGIC
184 || minixmagic(sb.ms) == MINIX_SUPER_MAGIC2
185 || minixmagic(sb.ms) == swapped(MINIX_SUPER_MAGIC2))
186 type = "minix";
187
188 else if (extmagic(sb.es) == EXT_SUPER_MAGIC)
189 type = "ext";
190
191 if (!type) {
192 if (lseek(fd, 0, SEEK_SET) != 0
193 || read(fd, (char *) &xsb, sizeof(xsb)) != sizeof(xsb))
194 goto io_error;
195
196 if (xiafsmagic(xsb.xiasb) == _XIAFS_SUPER_MAGIC)
197 type = "xiafs";
198 else if(!strncmp(xsb.romfs_magic, "-rom1fs-", 8))
199 type = "romfs";
200 else if(!strncmp(xsb.xfsb.s_magic, XFS_SUPER_MAGIC, 4) ||
201 !strncmp(xsb.xfsb.s_magic, XFS_SUPER_MAGIC2, 4))
202 type = "xfs";
203 else if(!strncmp(xsb.qnx4fs_magic+4, "QNX4FS", 6))
204 type = "qnx4fs";
205 else if(xsb.bfs_magic == 0x1badface)
206 type = "bfs";
207 else if(!strncmp(xsb.ntfssb.s_magic, NTFS_SUPER_MAGIC,
208 sizeof(xsb.ntfssb.s_magic)))
209 type = "ntfs";
210 else if(cramfsmagic(xsb.cramfssb) == CRAMFS_SUPER_MAGIC)
211 type = "cramfs";
212 else if ((!strncmp(xsb.fatsb.s_os, "MSDOS", 5) ||
213 !strncmp(xsb.fatsb.s_os, "MSWIN", 5) ||
214 !strncmp(xsb.fatsb.s_os, "MTOOL", 5) ||
215 !strncmp(xsb.fatsb.s_os, "mkdosfs", 7) ||
216 !strncmp(xsb.fatsb.s_os, "kmkdosfs", 8))
217 && (!strncmp(xsb.fatsb.s_fs, "FAT12 ", 8) ||
218 !strncmp(xsb.fatsb.s_fs, "FAT16 ", 8) ||
219 !strncmp(xsb.fatsb.s_fs2, "FAT32 ", 8)))
220 type = "vfat"; /* only guessing - might as well be fat or umsdos */
221 }
222
223 if (!type) {
224 if (lseek(fd, 8192, SEEK_SET) != 8192
225 || read(fd, (char *) &ufssb, sizeof(ufssb)) != sizeof(ufssb))
226 goto io_error;
227
228 if (ufsmagic(ufssb) == UFS_SUPER_MAGIC) /* also test swapped version? */
229 type = "ufs";
230 }
231
232 if (!type) {
233 if (lseek(fd, 0x8000, SEEK_SET) != 0x8000
234 || read(fd, (char *) &isosb, sizeof(isosb)) != sizeof(isosb))
235 goto io_error;
236
237 if(strncmp(isosb.iso.id, ISO_STANDARD_ID, sizeof(isosb.iso.id)) == 0
238 || strncmp(isosb.hs.id, HS_STANDARD_ID, sizeof(isosb.hs.id)) == 0)
239 type = "iso9660";
240 else if (may_be_udf(isosb.iso.id))
241 type = "udf";
242 }
243
244 if (!type) {
245 if (lseek(fd, 0x400, SEEK_SET) != 0x400
246 || read(fd, (char *) &hfssb, sizeof(hfssb)) != sizeof(hfssb))
247 goto io_error;
248
249 /* also check if block size is equal to 512 bytes,
250 since the hfs driver currently only has support
251 for block sizes of 512 bytes long, and to be
252 more accurate (sb magic is only a short int) */
253 if ((hfsmagic(hfssb) == HFS_SUPER_MAGIC &&
254 hfsblksize(hfssb) == 0x20000) ||
255 (swapped(hfsmagic(hfssb)) == HFS_SUPER_MAGIC &&
256 hfsblksize(hfssb) == 0x200))
257 type = "hfs";
258 }
259
260 if (!type) {
261 if (lseek(fd, 0x2000, SEEK_SET) != 0x2000
262 || read(fd, (char *) &hpfssb, sizeof(hpfssb)) != sizeof(hpfssb))
263 goto io_error;
264
265 if (hpfsmagic(hpfssb) == HPFS_SUPER_MAGIC)
266 type = "hpfs";
267 }
268
269 if (!type) {
270 if (lseek(fd, 0xc00, SEEK_SET) != 0xc00
271 || read(fd, (char *) &adfssb, sizeof(adfssb)) != sizeof(adfssb))
272 goto io_error;
273
274 /* only a weak test */
275 if (may_be_adfs((u_char *) &adfssb)
276 && (adfsblksize(adfssb) >= 8 &&
277 adfsblksize(adfssb) <= 10))
278 type = "adfs";
279 }
280
281 if (!type) {
282 /* perhaps the user tries to mount the swap space
283 on a new disk; warn her before she does mke2fs on it */
284 int pagesize = getpagesize();
285 int rd;
286 char buf[32768];
287
288 rd = pagesize;
289 if (rd < 8192)
290 rd = 8192;
291 if (rd > sizeof(buf))
292 rd = sizeof(buf);
293 if (lseek(fd, 0, SEEK_SET) != 0
294 || read(fd, buf, rd) != rd)
295 goto io_error;
296 if (may_be_swap(buf+pagesize) ||
297 may_be_swap(buf+4096) || may_be_swap(buf+8192))
298 type = "swap";
299 }
300
301 close (fd);
302 return(type);
303
304 io_error:
305 perror(device);
306 close(fd);
307 return 0;
308 }
309
310 char *
311 guess_fstype_from_superblock(const char *spec) {
312 char *type = fstype(spec);
313 if (verbose) {
314 printf (_("mount: you didn't specify a filesystem type for %s\n"),
315 spec);
316 if (!type)
317 printf (_(" I will try all types mentioned in %s or %s\n"),
318 ETC_FILESYSTEMS, PROC_FILESYSTEMS);
319 else if (!strcmp(type, "swap"))
320 printf (_(" and it looks like this is swapspace\n"));
321 else
322 printf (_(" I will try type %s\n"), type);
323 }
324 return type;
325 }
326
327 static char *
328 procfsnext(FILE *procfs) {
329 char line[100];
330 char fsname[100];
331
332 while (fgets(line, sizeof(line), procfs)) {
333 if (sscanf (line, "nodev %[^\n]\n", fsname) == 1) continue;
334 if (sscanf (line, " %[^ \n]\n", fsname) != 1) continue;
335 return strdup(fsname);
336 }
337 return 0;
338 }
339
340 /* Only use /proc/filesystems here, this is meant to test what
341 the kernel knows about, so /etc/filesystems is irrelevant.
342 Return: 1: yes, 0: no, -1: cannot open procfs */
343 int
344 is_in_procfs(const char *type) {
345 FILE *procfs;
346 char *fsname;
347 int ret = -1;
348
349 procfs = fopen(PROC_FILESYSTEMS, "r");
350 if (procfs) {
351 ret = 0;
352 while ((fsname = procfsnext(procfs)) != NULL)
353 if (!strcmp(fsname, type)) {
354 ret = 1;
355 break;
356 }
357 fclose(procfs);
358 procfs = NULL;
359 }
360 return ret;
361 }
362
363 /* return: 0: OK, -1: error in errno, 1: type not found */
364 /* when 1 is returned, *type is NULL */
365 int
366 procfsloop(int (*mount_fn)(struct mountargs *), struct mountargs *args,
367 char **type) {
368 FILE *procfs;
369 char *fsname;
370 int ret = 1;
371 int errsv = 0;
372
373 *type = NULL;
374
375 procfs = fopen(ETC_FILESYSTEMS, "r");
376 if (!procfs) {
377 procfs = fopen(PROC_FILESYSTEMS, "r");
378 if (!procfs)
379 return 1;
380 }
381 while ((fsname = procfsnext(procfs)) != NULL) {
382 if (tested (fsname))
383 continue;
384 args->type = fsname;
385 if (verbose) {
386 printf(_("Trying %s\n"), fsname);
387 fflush(stdout);
388 }
389 if ((*mount_fn) (args) == 0) {
390 *type = fsname;
391 ret = 0;
392 break;
393 } else if (errno != EINVAL && is_in_procfs(fsname) == 1) {
394 *type = "guess";
395 ret = -1;
396 errsv = errno;
397 break;
398 }
399 }
400 fclose(procfs);
401 errno = errsv;
402 return ret;
403 }