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>
20 #include <netinet/in.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 */
27 #include "cramfs_fs.h"
35 #include "iso9660_sb.h"
37 #if __BYTE_ORDER == __BIG_ENDIAN
38 #include <linux/byteorder/big_endian.h>
40 #include <linux/byteorder/little_endian.h>
42 #include "squashfs_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"
62 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
64 #define BLOCK_SIZE 1024
66 /* Swap needs the definition of block size */
69 static int jffs2_image(const void *buf
, unsigned long long *bytes
)
71 const unsigned char *p
= buf
;
73 if (*p
== 0x85 && p
[1] == 0x19)
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))
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 */
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;
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
);
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);
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
)) {
151 (unsigned long long) __le32_to_cpu(sb
->s_blocks_count_lo
)
152 << (10 + __le32_to_cpu(sb
->s_log_block_size
));
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
) &&
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
));
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
));
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
);
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
);
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
);
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
);
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 */
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
)) {
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
)) {
281 static int lvm2_image(const void *buf
, unsigned long long *blocks
)
283 const struct lvm2_super_block
*lsb
;
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 */
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
)) {
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
;
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) * ?; */
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)) {
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
);
374 int (*identify
) (const void *, unsigned long long *);
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
},
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
;
424 unsigned long long dummy
;
432 for (ip
= images
; ip
->identify
; ip
++) {
433 /* Hack for swap, which apparently is dependent on page size */
435 ip
->block
= SWAP_OFFSET();
437 if (cur_block
!= ip
->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
)) {
454 return 1; /* Unknown filesystem */