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