]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libdisk/fstype.c
Update copyright/license notices to match SGI legal prefered boilerplate.
[thirdparty/xfsprogs-dev.git] / libdisk / fstype.c
CommitLineData
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
47static inline unsigned short
48swapped(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
84static char
85*udf_magic[] = { "BEA01", "BOOT2", "CD001", "CDW02", "NSR02",
86 "NSR03", "TEA01" };
87
ebf3db3a 88
f937adac
NS
89static int
90may_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 */
100static int
101is_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
136static int
137may_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 */
143static int
144may_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
156static 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
164char *
165fstype(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
407io_error:
408 close(fd);
409 return 0;
410}