]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - libdisk/fstype.c
Update copyright dates (again)
[thirdparty/xfsprogs-dev.git] / libdisk / fstype.c
1 /*
2 * Copyright (c) 2000-2001 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 */
48
49 #define SIZE(a) (sizeof(a)/sizeof(a[0]))
50
51 static inline unsigned short
52 swapped(unsigned short a) {
53 return (a>>8) | (a<<8);
54 }
55
56 static inline int
57 assemble4le(unsigned char *p) {
58 return (p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24));
59 }
60
61 /*
62 Probes the device and attempts to determine the type of filesystem
63 contained within.
64
65 Original routine by <jmorriso@bogomips.ww.ubc.ca>; made into a function
66 for mount(8) by Mike Grupenhoff <kashmir@umiacs.umd.edu>.
67 Read the superblock only once - aeb
68 Added iso9660, romfs, qnx4, udf, swap - aeb
69 Added a test for high sierra (iso9660) - quinlan@bucknell.edu
70 Corrected the test for xiafs - aeb
71 Added ufs from a patch by jj. But maybe there are several types of ufs?
72 Added ntfs from a patch by Richard Russon.
73 Added a very weak heuristic for vfat - aeb
74 Added xfs - 2000-03-21 Martin K. Petersen <mkp@linuxcare.com>
75 Added cramfs, hfs, hpfs, adfs - Sepp Wijnands <mrrazz@garbage-coderz.net>
76 Added ext3 - Andrew Morton
77 */
78
79 /* udf magic - I find that trying to mount garbage as an udf fs
80 causes a very large kernel delay, almost killing the machine.
81 So, we do not try udf unless there is positive evidence that it
82 might work. Try iso9660 first, it is much more likely.
83 Strings below taken from ECMA 167. */
84 static char
85 *udf_magic[] = { "BEA01", "BOOT2", "CD001", "CDW02", "NSR02",
86 "NSR03", "TEA01" };
87
88 static int
89 may_be_udf(const char *id) {
90 char **m;
91
92 for (m = udf_magic; m - udf_magic < SIZE(udf_magic); m++)
93 if (!strncmp(*m, id, 5))
94 return 1;
95 return 0;
96 }
97
98 static int
99 may_be_swap(const char *s) {
100 return (strncmp(s-10, "SWAP-SPACE", 10) == 0 ||
101 strncmp(s-10, "SWAPSPACE2", 10) == 0);
102 }
103
104 /* rather weak necessary condition */
105 static int
106 may_be_adfs(const u_char *s) {
107 u_char *p;
108 int sum;
109
110 p = (u_char *) s + 511;
111 sum = 0;
112 while(--p != s)
113 sum = (sum >> 8) + (sum & 0xff) + *p;
114
115 return (sum == p[511]);
116 }
117
118 static int is_reiserfs_magic_string (struct reiserfs_super_block * rs)
119 {
120 return (!strncmp (rs->s_magic, REISERFS_SUPER_MAGIC_STRING,
121 strlen ( REISERFS_SUPER_MAGIC_STRING)) ||
122 !strncmp (rs->s_magic, REISER2FS_SUPER_MAGIC_STRING,
123 strlen ( REISER2FS_SUPER_MAGIC_STRING)));
124 }
125
126 char *
127 fstype(const char *device) {
128 int fd;
129 char *type = NULL;
130 union {
131 struct minix_super_block ms;
132 struct ext_super_block es;
133 struct ext2_super_block e2s;
134 struct reiserfs_super_block rs;
135 } sb;
136 union {
137 struct xiafs_super_block xiasb;
138 char romfs_magic[8];
139 char qnx4fs_magic[10]; /* ignore first 4 bytes */
140 long bfs_magic;
141 struct ntfs_super_block ntfssb;
142 struct fat_super_block fatsb;
143 struct xfs_super_block xfsb;
144 struct cramfs_super_block cramfssb;
145 } xsb;
146 struct ufs_super_block ufssb;
147 union {
148 struct iso_volume_descriptor iso;
149 struct hs_volume_descriptor hs;
150 } isosb;
151 struct hfs_super_block hfssb;
152 struct hpfs_super_block hpfssb;
153 struct adfs_super_block adfssb;
154 struct stat statbuf;
155
156 /* opening and reading an arbitrary unknown path can have
157 undesired side effects - first check that `device' refers
158 to a block device */
159 if (stat (device, &statbuf) || !S_ISBLK(statbuf.st_mode))
160 return 0;
161
162 fd = open(device, O_RDONLY);
163 if (fd < 0)
164 return 0;
165
166 if (lseek(fd, 1024, SEEK_SET) != 1024
167 || read(fd, (char *) &sb, sizeof(sb)) != sizeof(sb))
168 goto io_error;
169
170 /* ext2 has magic in little-endian on disk, so "swapped" is
171 superfluous; however, there have existed strange byteswapped
172 PPC ext2 systems */
173 if (ext2magic(sb.e2s) == EXT2_SUPER_MAGIC
174 || ext2magic(sb.e2s) == EXT2_PRE_02B_MAGIC
175 || ext2magic(sb.e2s) == swapped(EXT2_SUPER_MAGIC)) {
176 type = "ext2";
177
178 /* maybe even ext3? */
179 if ((assemble4le(sb.e2s.s_feature_compat)
180 & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
181 assemble4le(sb.e2s.s_journal_inum) != 0)
182 type = "ext3,ext2";
183 }
184
185 else if (minixmagic(sb.ms) == MINIX_SUPER_MAGIC
186 || minixmagic(sb.ms) == MINIX_SUPER_MAGIC2
187 || minixmagic(sb.ms) == swapped(MINIX_SUPER_MAGIC2))
188 type = "minix";
189
190 else if (extmagic(sb.es) == EXT_SUPER_MAGIC)
191 type = "ext";
192
193 if (!type) {
194 if (lseek(fd, REISERFS_DISK_OFFSET_IN_BYTES, SEEK_SET) !=
195 REISERFS_DISK_OFFSET_IN_BYTES
196 || read(fd, (char *) &sb, sizeof(sb)) != sizeof(sb))
197 goto io_error;
198 if (is_reiserfs_magic_string(&sb.rs))
199 type = "reiserfs";
200 }
201
202 if (!type) {
203 if (lseek(fd, REISERFS_OLD_DISK_OFFSET_IN_BYTES, SEEK_SET) !=
204 REISERFS_OLD_DISK_OFFSET_IN_BYTES
205 || read(fd, (char *) &sb, sizeof(sb)) != sizeof(sb))
206 goto io_error;
207 if (is_reiserfs_magic_string(&sb.rs))
208 type = "reiserfs";
209 }
210
211 if (!type) {
212 if (lseek(fd, 0, SEEK_SET) != 0
213 || read(fd, (char *) &xsb, sizeof(xsb)) != sizeof(xsb))
214 goto io_error;
215
216 if (xiafsmagic(xsb.xiasb) == _XIAFS_SUPER_MAGIC)
217 type = "xiafs";
218 else if(!strncmp(xsb.romfs_magic, "-rom1fs-", 8))
219 type = "romfs";
220 else if(!strncmp(xsb.xfsb.s_magic, XFS_SUPER_MAGIC, 4))
221 type = "xfs";
222 else if(!strncmp(xsb.qnx4fs_magic+4, "QNX4FS", 6))
223 type = "qnx4fs";
224 else if(xsb.bfs_magic == 0x1badface)
225 type = "bfs";
226 else if(!strncmp(xsb.ntfssb.s_magic, NTFS_SUPER_MAGIC,
227 sizeof(xsb.ntfssb.s_magic)))
228 type = "ntfs";
229 else if(cramfsmagic(xsb.cramfssb) == CRAMFS_SUPER_MAGIC)
230 type = "cramfs";
231 else if ((!strncmp(xsb.fatsb.s_os, "MSDOS", 5) ||
232 !strncmp(xsb.fatsb.s_os, "MSWIN", 5) ||
233 !strncmp(xsb.fatsb.s_os, "MTOOL", 5) ||
234 !strncmp(xsb.fatsb.s_os, "mkdosfs", 7) ||
235 !strncmp(xsb.fatsb.s_os, "kmkdosfs", 8) ||
236 /* Michal Svec: created by fdformat, old msdos utility for
237 formatting large (1.7) floppy disks. */
238 !strncmp(xsb.fatsb.s_os, "CH-FOR18", 8))
239 && (!strncmp(xsb.fatsb.s_fs, "FAT12 ", 8) ||
240 !strncmp(xsb.fatsb.s_fs, "FAT16 ", 8) ||
241 !strncmp(xsb.fatsb.s_fs2, "FAT32 ", 8)))
242 type = "vfat"; /* only guessing - might as well be fat or umsdos */
243 }
244
245 if (!type) {
246 if (lseek(fd, 8192, SEEK_SET) != 8192
247 || read(fd, (char *) &ufssb, sizeof(ufssb)) != sizeof(ufssb))
248 goto io_error;
249
250 if (ufsmagic(ufssb) == UFS_SUPER_MAGIC) /* also test swapped version? */
251 type = "ufs";
252 }
253
254 if (!type) {
255 if (lseek(fd, 0x8000, SEEK_SET) != 0x8000
256 || read(fd, (char *) &isosb, sizeof(isosb)) != sizeof(isosb))
257 goto io_error;
258
259 if(strncmp(isosb.iso.id, ISO_STANDARD_ID, sizeof(isosb.iso.id)) == 0
260 || strncmp(isosb.hs.id, HS_STANDARD_ID, sizeof(isosb.hs.id)) == 0)
261 type = "iso9660";
262 else if (may_be_udf(isosb.iso.id))
263 type = "udf";
264 }
265
266 if (!type) {
267 if (lseek(fd, 0x400, SEEK_SET) != 0x400
268 || read(fd, (char *) &hfssb, sizeof(hfssb)) != sizeof(hfssb))
269 goto io_error;
270
271 /* also check if block size is equal to 512 bytes,
272 since the hfs driver currently only has support
273 for block sizes of 512 bytes long, and to be
274 more accurate (sb magic is only a short int) */
275 if ((hfsmagic(hfssb) == HFS_SUPER_MAGIC &&
276 hfsblksize(hfssb) == 0x20000) ||
277 (swapped(hfsmagic(hfssb)) == HFS_SUPER_MAGIC &&
278 hfsblksize(hfssb) == 0x200))
279 type = "hfs";
280 }
281
282 if (!type) {
283 if (lseek(fd, 0x2000, SEEK_SET) != 0x2000
284 || read(fd, (char *) &hpfssb, sizeof(hpfssb)) != sizeof(hpfssb))
285 goto io_error;
286
287 if (hpfsmagic(hpfssb) == HPFS_SUPER_MAGIC)
288 type = "hpfs";
289 }
290
291 if (!type) {
292 if (lseek(fd, 0xc00, SEEK_SET) != 0xc00
293 || read(fd, (char *) &adfssb, sizeof(adfssb)) != sizeof(adfssb))
294 goto io_error;
295
296 /* only a weak test */
297 if (may_be_adfs((u_char *) &adfssb)
298 && (adfsblksize(adfssb) >= 8 &&
299 adfsblksize(adfssb) <= 10))
300 type = "adfs";
301 }
302
303 if (!type) {
304 /* perhaps the user tries to mount the swap space
305 on a new disk; warn her before she does mkfs on it */
306 int pagesize = getpagesize();
307 int rd;
308 char buf[32768];
309
310 rd = pagesize;
311 if (rd < 8192)
312 rd = 8192;
313 if (rd > sizeof(buf))
314 rd = sizeof(buf);
315 if (lseek(fd, 0, SEEK_SET) != 0
316 || read(fd, buf, rd) != rd)
317 goto io_error;
318 if (may_be_swap(buf+pagesize) ||
319 may_be_swap(buf+4096) || may_be_swap(buf+8192))
320 type = "swap";
321 }
322
323 close (fd);
324 return(type);
325
326 io_error:
327 close(fd);
328 return 0;
329 }