Set version to 0.2
[qi-bootmenu/guyou.git] / fstype / fstype.c
blobc3db82d6f3ee008e56e6d4469642581ac9790a7b
1 /*
2 * by rmk
4 * Detect filesystem type (on stdin) and output strings for two
5 * environment variables:
6 * FSTYPE - filesystem type
7 * FSSIZE - filesystem size (if known)
9 * We currently detect the filesystems listed below in the struct
10 * "imagetype images" (in the order they are listed).
13 #define _XOPEN_SOURCE 500
14 #include <sys/types.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <endian.h>
20 #include <netinet/in.h>
21 #include <sys/vfs.h>
22 #include <linux/types.h>
23 #include <asm/byteorder.h>
24 #define cpu_to_be32(x) __cpu_to_be32(x) /* Needed by romfs_fs.h */
26 #include "romfs_fs.h"
27 #include "cramfs_fs.h"
28 #include "minix_fs.h"
29 #include "ext2_fs.h"
30 #include "ext3_fs.h"
31 #include "ext4_fs.h"
32 #include "xfs_sb.h"
33 #include "luks_fs.h"
34 #include "lvm2_sb.h"
35 #include "iso9660_sb.h"
37 #if __BYTE_ORDER == __BIG_ENDIAN
38 #include <linux/byteorder/big_endian.h>
39 #else
40 #include <linux/byteorder/little_endian.h>
41 #endif
42 #include "squashfs_fs.h"
43 #include "gfs2_fs.h"
44 #include "ocfs2_fs.h"
45 #include "nilfs_fs.h"
48 * Slightly cleaned up version of jfs_superblock to
49 * avoid pulling in other kernel header files.
51 #include "jfs_superblock.h"
54 * reiserfs_fs.h is too sick to include directly.
55 * Use a cleaned up version.
57 #include "reiserfs_fs.h"
58 #include "reiser4_fs.h"
60 #include "fstype.h"
62 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
64 #define BLOCK_SIZE 1024
66 /* Swap needs the definition of block size */
67 #include "swap_fs.h"
69 static int jffs2_image(const void *buf, unsigned long long *bytes)
71 const unsigned char *p = buf;
72 // Very sloppy! ;-E
73 if (*p == 0x85 && p[1] == 0x19)
74 return 1;
76 return 0;
79 static int vfat_image(const void *buf, unsigned long long *bytes)
81 if (!strncmp(buf + 54, "FAT12 ", 8)
82 || !strncmp(buf + 54, "FAT16 ", 8)
83 || !strncmp(buf + 82, "FAT32 ", 8))
84 return 1;
86 return 0;
89 static int gzip_image(const void *buf, unsigned long long *bytes)
91 const unsigned char *p = buf;
93 if (p[0] == 037 && (p[1] == 0213 || p[1] == 0236)) {
94 /* The length of a gzip stream can only be determined
95 by processing the whole stream */
96 *bytes = 0ULL;
97 return 1;
99 return 0;
102 static int cramfs_image(const void *buf, unsigned long long *bytes)
104 const struct cramfs_super *sb = (const struct cramfs_super *)buf;
106 if (sb->magic == CRAMFS_MAGIC) {
107 if (sb->flags & CRAMFS_FLAG_FSID_VERSION_2)
108 *bytes = (unsigned long long)sb->fsid.blocks << 10;
109 else
110 *bytes = 0;
111 return 1;
113 return 0;
116 static int romfs_image(const void *buf, unsigned long long *bytes)
118 const struct romfs_super_block *sb =
119 (const struct romfs_super_block *)buf;
121 if (sb->word0 == ROMSB_WORD0 && sb->word1 == ROMSB_WORD1) {
122 *bytes = __be32_to_cpu(sb->size);
123 return 1;
125 return 0;
128 static int minix_image(const void *buf, unsigned long long *bytes)
130 const struct minix_super_block *sb =
131 (const struct minix_super_block *)buf;
133 if (sb->s_magic == MINIX_SUPER_MAGIC ||
134 sb->s_magic == MINIX_SUPER_MAGIC2) {
135 *bytes = (unsigned long long)sb->s_nzones
136 << (sb->s_log_zone_size + 10);
137 return 1;
139 return 0;
142 static int ext4_image(const void *buf, unsigned long long *bytes)
144 const struct ext4_super_block *sb =
145 (const struct ext4_super_block *) buf;
147 if (sb->s_magic == __cpu_to_le16(EXT4_SUPER_MAGIC) &&
148 sb->s_feature_compat & __cpu_to_le32(EXT4_FEATURE_COMPAT_HAS_JOURNAL) &&
149 sb->s_feature_incompat & __cpu_to_le32(EXT4_FEATURE_INCOMPAT_EXTENTS)) {
150 *bytes =
151 (unsigned long long) __le32_to_cpu(sb->s_blocks_count_lo)
152 << (10 + __le32_to_cpu(sb->s_log_block_size));
153 return 1;
155 return 0;
158 static int ext3_image(const void *buf, unsigned long long *bytes)
160 const struct ext3_super_block *sb =
161 (const struct ext3_super_block *)buf;
163 if (sb->s_magic == __cpu_to_le16(EXT2_SUPER_MAGIC) &&
164 sb->
165 s_feature_compat & __cpu_to_le32(EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
166 *bytes = (unsigned long long)__le32_to_cpu(sb->s_blocks_count)
167 << (10 + __le32_to_cpu(sb->s_log_block_size));
168 return 1;
170 return 0;
173 static int ext2_image(const void *buf, unsigned long long *bytes)
175 const struct ext2_super_block *sb =
176 (const struct ext2_super_block *)buf;
178 if (sb->s_magic == __cpu_to_le16(EXT2_SUPER_MAGIC)) {
179 *bytes = (unsigned long long)__le32_to_cpu(sb->s_blocks_count)
180 << (10 + __le32_to_cpu(sb->s_log_block_size));
181 return 1;
183 return 0;
186 static int reiserfs_image(const void *buf, unsigned long long *bytes)
188 const struct reiserfs_super_block *sb =
189 (const struct reiserfs_super_block *)buf;
191 if (memcmp(REISERFS_MAGIC(sb), REISERFS_SUPER_MAGIC_STRING,
192 sizeof(REISERFS_SUPER_MAGIC_STRING) - 1) == 0 ||
193 memcmp(REISERFS_MAGIC(sb), REISER2FS_SUPER_MAGIC_STRING,
194 sizeof(REISER2FS_SUPER_MAGIC_STRING) - 1) == 0 ||
195 memcmp(REISERFS_MAGIC(sb), REISER2FS_JR_SUPER_MAGIC_STRING,
196 sizeof(REISER2FS_JR_SUPER_MAGIC_STRING) - 1) == 0) {
197 *bytes = (unsigned long long)REISERFS_BLOCK_COUNT(sb) *
198 REISERFS_BLOCKSIZE(sb);
199 return 1;
201 return 0;
204 static int reiser4_image(const void *buf, unsigned long long *bytes)
206 const struct reiser4_master_sb *sb =
207 (const struct reiser4_master_sb *)buf;
209 if (memcmp(sb->ms_magic, REISER4_SUPER_MAGIC_STRING,
210 sizeof(REISER4_SUPER_MAGIC_STRING) - 1) == 0) {
211 *bytes = (unsigned long long) __le32_to_cpu(sb->ms_format) *
212 __le32_to_cpu(sb->ms_blksize);
213 return 1;
215 return 0;
218 static int xfs_image(const void *buf, unsigned long long *bytes)
220 const struct xfs_sb *sb = (const struct xfs_sb *)buf;
222 if (__be32_to_cpu(sb->sb_magicnum) == XFS_SB_MAGIC) {
223 *bytes = __be64_to_cpu(sb->sb_dblocks) *
224 __be32_to_cpu(sb->sb_blocksize);
225 return 1;
227 return 0;
230 static int jfs_image(const void *buf, unsigned long long *bytes)
232 const struct jfs_superblock *sb = (const struct jfs_superblock *)buf;
234 if (!memcmp(sb->s_magic, JFS_MAGIC, 4)) {
235 *bytes = __le64_to_cpu(sb->s_size) << __le16_to_cpu(sb->s_l2pbsize);
236 return 1;
238 return 0;
241 static int luks_image(const void *buf, unsigned long long *blocks)
243 const struct luks_partition_header *lph =
244 (const struct luks_partition_header *)buf;
246 if (!memcmp(lph->magic, LUKS_MAGIC, LUKS_MAGIC_L)) {
247 /* FSSIZE is dictated by the underlying fs, not by LUKS */
248 *blocks = 0;
249 return 1;
251 return 0;
254 static int swap_image(const void *buf, unsigned long long *blocks)
256 const struct swap_super_block *ssb =
257 (const struct swap_super_block *)buf;
259 if (!memcmp(ssb->magic, SWAP_MAGIC_1, SWAP_MAGIC_L) ||
260 !memcmp(ssb->magic, SWAP_MAGIC_2, SWAP_MAGIC_L)) {
261 *blocks = 0;
262 return 1;
264 return 0;
267 static int suspend_image(const void *buf, unsigned long long *blocks)
269 const struct swap_super_block *ssb =
270 (const struct swap_super_block *)buf;
272 if (!memcmp(ssb->magic, SUSP_MAGIC_1, SUSP_MAGIC_L) ||
273 !memcmp(ssb->magic, SUSP_MAGIC_2, SUSP_MAGIC_L) ||
274 !memcmp(ssb->magic, SUSP_MAGIC_U, SUSP_MAGIC_L)) {
275 *blocks = 0;
276 return 1;
278 return 0;
281 static int lvm2_image(const void *buf, unsigned long long *blocks)
283 const struct lvm2_super_block *lsb;
284 int i;
286 /* We must check every 512 byte sector */
287 for (i = 0; i < BLOCK_SIZE; i += 0x200) {
288 lsb = (const struct lvm2_super_block *)(buf + i);
290 if (!memcmp(lsb->magic, LVM2_MAGIC, LVM2_MAGIC_L) &&
291 !memcmp(lsb->type, LVM2_TYPE, LVM2_TYPE_L)) {
292 /* This is just one of possibly many PV's */
293 *blocks = 0;
294 return 1;
298 return 0;
301 static int iso_image(const void *buf, unsigned long long *blocks)
303 const struct iso_volume_descriptor *isovd =
304 (const struct iso_volume_descriptor *)buf;
305 const struct iso_hs_volume_descriptor *isohsvd =
306 (const struct iso_hs_volume_descriptor *)buf;
308 if (!memcmp(isovd->id, ISO_MAGIC, ISO_MAGIC_L) ||
309 !memcmp(isohsvd->id, ISO_HS_MAGIC, ISO_HS_MAGIC_L)) {
310 *blocks = 0;
311 return 1;
313 return 0;
316 static int squashfs_image(const void *buf, unsigned long long *blocks)
318 const struct squashfs_super_block *sb =
319 (const struct squashfs_super_block *)buf;
321 if (sb->s_magic == SQUASHFS_MAGIC
322 || sb->s_magic == SQUASHFS_MAGIC_SWAP
323 || sb->s_magic == SQUASHFS_MAGIC_LZMA
324 || sb->s_magic == SQUASHFS_MAGIC_LZMA_SWAP) {
325 *blocks = (unsigned long long) sb->bytes_used;
326 return 1;
328 return 0;
331 static int gfs2_image(const void *buf, unsigned long long *bytes)
333 const struct gfs2_sb *sb =
334 (const struct gfs2_sb *)buf;
336 if (__be32_to_cpu(sb->sb_header.mh_magic) == GFS2_MAGIC
337 && (__be32_to_cpu(sb->sb_fs_format) == GFS2_FORMAT_FS
338 || __be32_to_cpu(sb->sb_fs_format) == GFS2_FORMAT_MULTI)) {
339 *bytes = 0; /* cpu_to_be32(sb->sb_bsize) * ?; */
340 return 1;
342 return 0;
345 static int ocfs2_image(const void *buf, unsigned long long *bytes)
347 const struct ocfs2_dinode *sb =
348 (const struct ocfs2_dinode *)buf;
350 if (!memcmp(sb->i_signature, OCFS2_SUPER_BLOCK_SIGNATURE,
351 sizeof(OCFS2_SUPER_BLOCK_SIGNATURE) - 1)) {
352 *bytes = 0;
353 return 1;
355 return 0;
358 static int nilfs2_image(const void *buf, unsigned long long *bytes)
360 const struct nilfs_super_block *sb =
361 (const struct nilfs_super_block *)buf;
363 if (sb->s_magic == __cpu_to_le16(NILFS_SUPER_MAGIC) &&
364 sb->s_rev_level == __cpu_to_le32(2)) {
365 *bytes = (unsigned long long)__le64_to_cpu(sb->s_dev_size);
366 return 1;
368 return 0;
371 struct imagetype {
372 off_t block;
373 const char name[12];
374 int (*identify) (const void *, unsigned long long *);
378 * Note:
380 * Minix test needs to come after ext3/ext2, since it's possible for
381 * ext3/ext2 to look like minix by pure random chance.
383 * LVM comes after all other filesystems since it's possible
384 * that an old lvm signature is left on the disk if pvremove
385 * is not used before creating the new fs.
387 * The same goes for LUKS as for LVM.
389 static struct imagetype images[] = {
390 {1, "ext4", ext4_image},
391 {1, "ext3", ext3_image},
392 {1, "ext2", ext2_image},
393 {0, "jffs2", jffs2_image},
394 {0, "vfat", vfat_image},
395 {0, "gzip", gzip_image},
396 {0, "cramfs", cramfs_image},
397 {0, "romfs", romfs_image},
398 {0, "xfs", xfs_image},
399 {0, "squashfs", squashfs_image},
400 {1, "minix", minix_image},
401 {1, "nilfs2", nilfs2_image},
402 {2, "ocfs2", ocfs2_image},
403 {8, "reiserfs", reiserfs_image},
404 {64, "reiserfs", reiserfs_image},
405 {64, "reiser4", reiser4_image},
406 {64, "gfs2", gfs2_image},
407 {32, "jfs", jfs_image},
408 {32, "iso9660", iso_image},
409 {0, "luks", luks_image},
410 {0, "lvm2", lvm2_image},
411 {1, "lvm2", lvm2_image},
412 {-1, "swap", swap_image},
413 {-1, "suspend", suspend_image},
414 {0, "", NULL}
417 int identify_fs(int fd, const char **fstype,
418 unsigned long long *bytes, off_t offset)
420 uint64_t buf[BLOCK_SIZE >> 3]; /* 64-bit worst case alignment */
421 off_t cur_block = (off_t) - 1;
422 struct imagetype *ip;
423 int ret;
424 unsigned long long dummy;
426 if (!bytes)
427 bytes = &dummy;
429 *fstype = NULL;
430 *bytes = 0;
432 for (ip = images; ip->identify; ip++) {
433 /* Hack for swap, which apparently is dependent on page size */
434 if (ip->block == -1)
435 ip->block = SWAP_OFFSET();
437 if (cur_block != ip->block) {
439 * Read block.
441 cur_block = ip->block;
442 ret = pread(fd, buf, BLOCK_SIZE,
443 offset + cur_block * BLOCK_SIZE);
444 if (ret != BLOCK_SIZE)
445 return -1; /* error */
448 if (ip->identify(buf, bytes)) {
449 *fstype = ip->name;
450 return 0;
454 return 1; /* Unknown filesystem */