]>
Commit | Line | Data |
---|---|---|
f937adac | 1 | /* |
da23017d NS |
2 | * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. |
3 | * All Rights Reserved. | |
dfc130f3 | 4 | * |
da23017d NS |
5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License as | |
f937adac | 7 | * published by the Free Software Foundation. |
dfc130f3 | 8 | * |
da23017d NS |
9 | * This program is distributed in the hope that it would be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
dfc130f3 | 13 | * |
da23017d NS |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write the Free Software Foundation, | |
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
f937adac NS |
17 | */ |
18 | ||
19 | #include <stdio.h> | |
20 | #include <fcntl.h> | |
21 | #include <unistd.h> | |
22 | #include <stdlib.h> | |
23 | #include <string.h> | |
24 | #include <sys/stat.h> | |
25 | #include "fstype.h" | |
26 | ||
27 | /* | |
28 | * From mount(8) source by Andries Brouwer. Hacked for XFS by mkp. | |
29 | * Recent sync's to mount source: | |
30 | * - util-linux-2.10o ... 06 Sep 00 | |
31 | * - util-linux-2.10r ... 06 Dec 00 | |
32 | * - util-linux-2.11g ... 02 Jul 01 | |
ebf3db3a | 33 | * - util-linux-2.11u ... 24 Aug 02 |
1cba5ede | 34 | * - util-linux-2.11z ... 13 May 03 |
f937adac NS |
35 | */ |
36 | ||
37 | #define SIZE(a) (sizeof(a)/sizeof(a[0])) | |
38 | ||
ebf3db3a ES |
39 | /* Most file system types can be recognized by a `magic' number |
40 | in the superblock. Note that the order of the tests is | |
41 | significant: by coincidence a filesystem can have the | |
42 | magic numbers for several file system types simultaneously. | |
43 | For example, the romfs magic lives in the 1st sector; | |
44 | xiafs does not touch the 1st sector and has its magic in | |
45 | the 2nd sector; ext2 does not touch the first two sectors. */ | |
46 | ||
f937adac NS |
47 | static inline unsigned short |
48 | swapped(unsigned short a) { | |
49 | return (a>>8) | (a<<8); | |
50 | } | |
51 | ||
f937adac NS |
52 | /* |
53 | Probes the device and attempts to determine the type of filesystem | |
54 | contained within. | |
55 | ||
56 | Original routine by <jmorriso@bogomips.ww.ubc.ca>; made into a function | |
57 | for mount(8) by Mike Grupenhoff <kashmir@umiacs.umd.edu>. | |
ebf3db3a | 58 | Corrected the test for xiafs - aeb |
f937adac | 59 | Read the superblock only once - aeb |
ebf3db3a ES |
60 | Added a very weak heuristic for vfat - aeb |
61 | Added iso9660, minix-v2, romfs, qnx4, udf, vxfs, swap - aeb | |
f937adac | 62 | Added a test for high sierra (iso9660) - quinlan@bucknell.edu |
f937adac NS |
63 | Added ufs from a patch by jj. But maybe there are several types of ufs? |
64 | Added ntfs from a patch by Richard Russon. | |
f937adac NS |
65 | Added xfs - 2000-03-21 Martin K. Petersen <mkp@linuxcare.com> |
66 | Added cramfs, hfs, hpfs, adfs - Sepp Wijnands <mrrazz@garbage-coderz.net> | |
67 | Added ext3 - Andrew Morton | |
ebf3db3a ES |
68 | Added jfs - Christoph Hellwig |
69 | Added sysv - Tim Launchbury | |
70 | Added udf - Bryce Nesbitt | |
f937adac NS |
71 | */ |
72 | ||
ebf3db3a ES |
73 | /* |
74 | * udf magic - I find that trying to mount garbage as an udf fs | |
75 | * causes a very large kernel delay, almost killing the machine. | |
76 | * So, we do not try udf unless there is positive evidence that it | |
77 | * might work. Strings below taken from ECMA 167. | |
78 | */ | |
79 | /* | |
80 | * It seems that before udf 2.00 the volume descriptor was not well | |
81 | * defined. For 2.00 you're supposed to keep scanning records until | |
82 | * you find one NOT in this list. (See ECMA 2/8.3.1). | |
83 | */ | |
f937adac NS |
84 | static char |
85 | *udf_magic[] = { "BEA01", "BOOT2", "CD001", "CDW02", "NSR02", | |
86 | "NSR03", "TEA01" }; | |
87 | ||
ebf3db3a | 88 | |
f937adac NS |
89 | static int |
90 | may_be_udf(const char *id) { | |
91 | char **m; | |
92 | ||
93 | for (m = udf_magic; m - udf_magic < SIZE(udf_magic); m++) | |
94 | if (!strncmp(*m, id, 5)) | |
95 | return 1; | |
96 | return 0; | |
97 | } | |
98 | ||
ebf3db3a ES |
99 | /* we saw "CD001" - may be iso9660 or udf - Bryce Nesbitt */ |
100 | static int | |
101 | is_really_udf(int fd) { | |
102 | int j, bs; | |
103 | struct iso_volume_descriptor isosb; | |
104 | ||
105 | /* determine the block size by scanning in 2K increments | |
106 | (block sizes larger than 2K will be null padded) */ | |
107 | for (bs = 1; bs < 16; bs++) { | |
108 | lseek(fd, bs*2048+32768, SEEK_SET); | |
109 | if (read(fd, (char *)&isosb, sizeof(isosb)) != sizeof(isosb)) | |
110 | return 0; | |
111 | if (isosb.id[0]) | |
112 | break; | |
113 | } | |
114 | ||
115 | /* Scan up to another 64 blocks looking for additional VSD's */ | |
116 | for (j = 1; j < 64; j++) { | |
117 | if (j > 1) { | |
118 | lseek(fd, j*bs*2048+32768, SEEK_SET); | |
119 | if (read(fd, (char *)&isosb, sizeof(isosb)) | |
120 | != sizeof(isosb)) | |
121 | return 0; | |
122 | } | |
123 | /* If we find NSR0x then call it udf: | |
124 | NSR01 for UDF 1.00 | |
125 | NSR02 for UDF 1.50 | |
126 | NSR03 for UDF 2.00 */ | |
127 | if (!strncmp(isosb.id, "NSR0", 4)) | |
128 | return 1; | |
129 | if (!may_be_udf(isosb.id)) | |
130 | return 0; | |
131 | } | |
132 | ||
133 | return 0; | |
134 | } | |
135 | ||
f937adac NS |
136 | static int |
137 | may_be_swap(const char *s) { | |
138 | return (strncmp(s-10, "SWAP-SPACE", 10) == 0 || | |
139 | strncmp(s-10, "SWAPSPACE2", 10) == 0); | |
140 | } | |
141 | ||
142 | /* rather weak necessary condition */ | |
143 | static int | |
144 | may_be_adfs(const u_char *s) { | |
145 | u_char *p; | |
146 | int sum; | |
147 | ||
148 | p = (u_char *) s + 511; | |
149 | sum = 0; | |
150 | while(--p != s) | |
151 | sum = (sum >> 8) + (sum & 0xff) + *p; | |
152 | ||
153 | return (sum == p[511]); | |
154 | } | |
155 | ||
156 | static int is_reiserfs_magic_string (struct reiserfs_super_block * rs) | |
157 | { | |
1cba5ede | 158 | return (!strncmp (rs->s_magic, REISERFS_SUPER_MAGIC_STRING, |
f937adac | 159 | strlen ( REISERFS_SUPER_MAGIC_STRING)) || |
1cba5ede | 160 | !strncmp (rs->s_magic, REISER2FS_SUPER_MAGIC_STRING, |
f937adac NS |
161 | strlen ( REISER2FS_SUPER_MAGIC_STRING))); |
162 | } | |
163 | ||
164 | char * | |
165 | fstype(const char *device) { | |
166 | int fd; | |
167 | char *type = NULL; | |
168 | union { | |
169 | struct minix_super_block ms; | |
170 | struct ext_super_block es; | |
171 | struct ext2_super_block e2s; | |
ebf3db3a | 172 | struct vxfs_super_block vs; |
638473d8 | 173 | struct hfs_super_block hs; |
ebf3db3a | 174 | } sb; /* stuff at 1024 */ |
f937adac NS |
175 | union { |
176 | struct xiafs_super_block xiasb; | |
177 | char romfs_magic[8]; | |
178 | char qnx4fs_magic[10]; /* ignore first 4 bytes */ | |
638473d8 | 179 | unsigned int bfs_magic; |
f937adac NS |
180 | struct ntfs_super_block ntfssb; |
181 | struct fat_super_block fatsb; | |
182 | struct xfs_super_block xfsb; | |
183 | struct cramfs_super_block cramfssb; | |
184 | } xsb; | |
185 | struct ufs_super_block ufssb; | |
186 | union { | |
187 | struct iso_volume_descriptor iso; | |
188 | struct hs_volume_descriptor hs; | |
189 | } isosb; | |
ebf3db3a ES |
190 | struct reiserfs_super_block reiserfssb; /* block 64 or 8 */ |
191 | struct jfs_super_block jfssb; /* block 32 */ | |
f937adac NS |
192 | struct hpfs_super_block hpfssb; |
193 | struct adfs_super_block adfssb; | |
ebf3db3a | 194 | struct sysv_super_block svsb; |
f937adac NS |
195 | struct stat statbuf; |
196 | ||
197 | /* opening and reading an arbitrary unknown path can have | |
198 | undesired side effects - first check that `device' refers | |
ebf3db3a ES |
199 | to a block device or ordinary file */ |
200 | if (stat (device, &statbuf) || | |
201 | !(S_ISBLK(statbuf.st_mode) || S_ISREG(statbuf.st_mode))) | |
f937adac NS |
202 | return 0; |
203 | ||
204 | fd = open(device, O_RDONLY); | |
205 | if (fd < 0) | |
206 | return 0; | |
207 | ||
ebf3db3a ES |
208 | /* do seeks and reads in disk order, otherwise a very short |
209 | partition may cause a failure because of read error */ | |
f937adac NS |
210 | |
211 | if (!type) { | |
ebf3db3a | 212 | /* block 0 */ |
f937adac NS |
213 | if (lseek(fd, 0, SEEK_SET) != 0 |
214 | || read(fd, (char *) &xsb, sizeof(xsb)) != sizeof(xsb)) | |
1cba5ede NS |
215 | goto try_iso9660; |
216 | /* Gyorgy Kovesdi: none of my photocds has a readable block 0 */ | |
f937adac NS |
217 | |
218 | if (xiafsmagic(xsb.xiasb) == _XIAFS_SUPER_MAGIC) | |
219 | type = "xiafs"; | |
220 | else if(!strncmp(xsb.romfs_magic, "-rom1fs-", 8)) | |
221 | type = "romfs"; | |
222 | else if(!strncmp(xsb.xfsb.s_magic, XFS_SUPER_MAGIC, 4)) | |
223 | type = "xfs"; | |
224 | else if(!strncmp(xsb.qnx4fs_magic+4, "QNX4FS", 6)) | |
ebf3db3a | 225 | type = "qnx4"; |
f937adac NS |
226 | else if(xsb.bfs_magic == 0x1badface) |
227 | type = "bfs"; | |
228 | else if(!strncmp(xsb.ntfssb.s_magic, NTFS_SUPER_MAGIC, | |
229 | sizeof(xsb.ntfssb.s_magic))) | |
230 | type = "ntfs"; | |
1cba5ede NS |
231 | else if(cramfsmagic(xsb.cramfssb) == CRAMFS_SUPER_MAGIC || |
232 | cramfsmagic(xsb.cramfssb) == CRAMFS_SUPER_MAGIC_BE) | |
f937adac NS |
233 | type = "cramfs"; |
234 | else if ((!strncmp(xsb.fatsb.s_os, "MSDOS", 5) || | |
235 | !strncmp(xsb.fatsb.s_os, "MSWIN", 5) || | |
236 | !strncmp(xsb.fatsb.s_os, "MTOOL", 5) || | |
237 | !strncmp(xsb.fatsb.s_os, "mkdosfs", 7) || | |
238 | !strncmp(xsb.fatsb.s_os, "kmkdosfs", 8) || | |
239 | /* Michal Svec: created by fdformat, old msdos utility for | |
240 | formatting large (1.7) floppy disks. */ | |
241 | !strncmp(xsb.fatsb.s_os, "CH-FOR18", 8)) | |
242 | && (!strncmp(xsb.fatsb.s_fs, "FAT12 ", 8) || | |
243 | !strncmp(xsb.fatsb.s_fs, "FAT16 ", 8) || | |
244 | !strncmp(xsb.fatsb.s_fs2, "FAT32 ", 8))) | |
245 | type = "vfat"; /* only guessing - might as well be fat or umsdos */ | |
246 | } | |
247 | ||
248 | if (!type) { | |
ebf3db3a ES |
249 | /* sector 1 */ |
250 | if (lseek(fd, 512 , SEEK_SET) != 512 | |
251 | || read(fd, (char *) &svsb, sizeof(svsb)) != sizeof(svsb)) | |
252 | goto io_error; | |
253 | if (sysvmagic(svsb) == SYSV_SUPER_MAGIC ) | |
254 | type = "sysv"; | |
f937adac NS |
255 | } |
256 | ||
257 | if (!type) { | |
ebf3db3a ES |
258 | /* block 1 */ |
259 | if (lseek(fd, 1024, SEEK_SET) != 1024 || | |
260 | read(fd, (char *) &sb, sizeof(sb)) != sizeof(sb)) | |
261 | goto io_error; | |
262 | ||
263 | /* ext2 has magic in little-endian on disk, so "swapped" is | |
264 | superfluous; however, there have existed strange byteswapped | |
265 | PPC ext2 systems */ | |
266 | if (ext2magic(sb.e2s) == EXT2_SUPER_MAGIC || | |
267 | ext2magic(sb.e2s) == EXT2_PRE_02B_MAGIC || | |
268 | ext2magic(sb.e2s) == swapped(EXT2_SUPER_MAGIC)) { | |
269 | type = "ext2"; | |
270 | ||
271 | /* maybe even ext3? */ | |
272 | if ((assemble4le(sb.e2s.s_feature_compat) | |
273 | & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && | |
274 | assemble4le(sb.e2s.s_journal_inum) != 0) | |
275 | type = "ext3"; /* "ext3,ext2" */ | |
276 | } | |
277 | ||
278 | else if (minixmagic(sb.ms) == MINIX_SUPER_MAGIC || | |
279 | minixmagic(sb.ms) == MINIX_SUPER_MAGIC2 || | |
280 | minixmagic(sb.ms) == swapped(MINIX_SUPER_MAGIC2) || | |
281 | minixmagic(sb.ms) == MINIX2_SUPER_MAGIC || | |
282 | minixmagic(sb.ms) == MINIX2_SUPER_MAGIC2) | |
283 | type = "minix"; | |
284 | ||
285 | else if (extmagic(sb.es) == EXT_SUPER_MAGIC) | |
286 | type = "ext"; | |
287 | ||
288 | else if (vxfsmagic(sb.vs) == VXFS_SUPER_MAGIC) | |
289 | type = "vxfs"; | |
1cba5ede | 290 | |
638473d8 NS |
291 | else if (hfsmagic(sb.hs) == swapped(HFS_SUPER_MAGIC) || |
292 | (hfsmagic(sb.hs) == swapped(HFSPLUS_SUPER_MAGIC) && | |
293 | hfsversion(sb.hs) == swapped(HFSPLUS_SUPER_VERSION))) | |
294 | type = "hfs"; | |
f937adac NS |
295 | } |
296 | ||
297 | if (!type) { | |
ebf3db3a | 298 | /* block 3 */ |
1cba5ede NS |
299 | if (lseek(fd, 0xc00, SEEK_SET) != 0xc00 |
300 | || read(fd, (char *) &adfssb, sizeof(adfssb)) != sizeof(adfssb)) | |
301 | goto io_error; | |
ebf3db3a ES |
302 | |
303 | /* only a weak test */ | |
1cba5ede NS |
304 | if (may_be_adfs((u_char *) &adfssb) |
305 | && (adfsblksize(adfssb) >= 8 && | |
306 | adfsblksize(adfssb) <= 10)) | |
307 | type = "adfs"; | |
ebf3db3a ES |
308 | } |
309 | ||
310 | if (!type) { | |
311 | int mag; | |
312 | ||
313 | /* block 8 */ | |
314 | if (lseek(fd, 8192, SEEK_SET) != 8192 | |
315 | || read(fd, (char *) &ufssb, sizeof(ufssb)) != sizeof(ufssb)) | |
316 | goto io_error; | |
317 | ||
318 | mag = ufsmagic(ufssb); | |
319 | if (mag == UFS_SUPER_MAGIC_LE || mag == UFS_SUPER_MAGIC_BE) | |
320 | type = "ufs"; | |
321 | } | |
322 | ||
323 | if (!type) { | |
324 | /* block 8 */ | |
325 | if (lseek(fd, REISERFS_OLD_DISK_OFFSET_IN_BYTES, SEEK_SET) != | |
326 | REISERFS_OLD_DISK_OFFSET_IN_BYTES | |
327 | || read(fd, (char *) &reiserfssb, sizeof(reiserfssb)) != | |
328 | sizeof(reiserfssb)) | |
329 | goto io_error; | |
330 | if (is_reiserfs_magic_string(&reiserfssb)) | |
331 | type = "reiserfs"; | |
332 | } | |
333 | ||
334 | if (!type) { | |
335 | /* block 8 */ | |
1cba5ede NS |
336 | if (lseek(fd, 0x2000, SEEK_SET) != 0x2000 |
337 | || read(fd, (char *) &hpfssb, sizeof(hpfssb)) != sizeof(hpfssb)) | |
338 | goto io_error; | |
f937adac | 339 | |
1cba5ede NS |
340 | if (hpfsmagic(hpfssb) == HPFS_SUPER_MAGIC) |
341 | type = "hpfs"; | |
f937adac NS |
342 | } |
343 | ||
344 | if (!type) { | |
ebf3db3a ES |
345 | /* block 32 */ |
346 | if (lseek(fd, JFS_SUPER1_OFF, SEEK_SET) != JFS_SUPER1_OFF | |
347 | || read(fd, (char *) &jfssb, sizeof(jfssb)) != sizeof(jfssb)) | |
348 | goto io_error; | |
349 | if (!strncmp(jfssb.s_magic, JFS_MAGIC, 4)) | |
350 | type = "jfs"; | |
351 | } | |
f937adac | 352 | |
ebf3db3a ES |
353 | if (!type) { |
354 | /* block 32 */ | |
1cba5ede | 355 | try_iso9660: |
ebf3db3a ES |
356 | if (lseek(fd, 0x8000, SEEK_SET) != 0x8000 |
357 | || read(fd, (char *) &isosb, sizeof(isosb)) != sizeof(isosb)) | |
358 | goto io_error; | |
359 | ||
360 | if (strncmp(isosb.hs.id, HS_STANDARD_ID, sizeof(isosb.hs.id)) == 0) { | |
361 | /* "CDROM" */ | |
362 | type = "iso9660"; | |
363 | } else if (strncmp(isosb.iso.id, ISO_STANDARD_ID, | |
364 | sizeof(isosb.iso.id)) == 0) { | |
365 | /* CD001 */ | |
366 | type = "iso9660"; | |
367 | if (is_really_udf(fd)) | |
368 | type = "udf"; | |
369 | } else if (may_be_udf(isosb.iso.id)) | |
370 | type = "udf"; | |
371 | } | |
372 | ||
373 | if (!type) { | |
374 | /* block 64 */ | |
375 | if (lseek(fd, REISERFS_DISK_OFFSET_IN_BYTES, SEEK_SET) != | |
376 | REISERFS_DISK_OFFSET_IN_BYTES | |
377 | || read(fd, (char *) &reiserfssb, sizeof(reiserfssb)) != | |
378 | sizeof(reiserfssb)) | |
379 | goto io_error; | |
380 | if (is_reiserfs_magic_string(&reiserfssb)) | |
381 | type = "reiserfs"; | |
f937adac NS |
382 | } |
383 | ||
384 | if (!type) { | |
385 | /* perhaps the user tries to mount the swap space | |
ebf3db3a | 386 | on a new disk; warn her before she does mke2fs on it */ |
f937adac NS |
387 | int pagesize = getpagesize(); |
388 | int rd; | |
389 | char buf[32768]; | |
390 | ||
391 | rd = pagesize; | |
392 | if (rd < 8192) | |
393 | rd = 8192; | |
394 | if (rd > sizeof(buf)) | |
395 | rd = sizeof(buf); | |
396 | if (lseek(fd, 0, SEEK_SET) != 0 | |
397 | || read(fd, buf, rd) != rd) | |
398 | goto io_error; | |
399 | if (may_be_swap(buf+pagesize) || | |
400 | may_be_swap(buf+4096) || may_be_swap(buf+8192)) | |
401 | type = "swap"; | |
402 | } | |
403 | ||
404 | close (fd); | |
405 | return(type); | |
406 | ||
407 | io_error: | |
408 | close(fd); | |
409 | return 0; | |
410 | } |