2 * Copyright (C) 1999, 2001 by Andries Brouwer
3 * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
4 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
6 * This file may be redistributed under the terms of the
7 * GNU Lesser General Public License.
17 #include <sys/utsname.h>
21 #include "linux_version.h"
22 #include "superblocks.h"
24 struct ext2_super_block
{
25 uint32_t s_inodes_count
;
26 uint32_t s_blocks_count
;
27 uint32_t s_r_blocks_count
;
28 uint32_t s_free_blocks_count
;
29 uint32_t s_free_inodes_count
;
30 uint32_t s_first_data_block
;
31 uint32_t s_log_block_size
;
33 unsigned char s_magic
[2];
36 uint16_t s_minor_rev_level
;
38 uint32_t s_checkinterval
;
39 uint32_t s_creator_os
;
41 uint16_t s_def_resuid
;
42 uint16_t s_def_resgid
;
44 uint16_t s_inode_size
;
45 uint16_t s_block_group_nr
;
46 uint32_t s_feature_compat
;
47 uint32_t s_feature_incompat
;
48 uint32_t s_feature_ro_compat
;
49 unsigned char s_uuid
[16];
50 char s_volume_name
[16];
51 char s_last_mounted
[64];
52 uint32_t s_algorithm_usage_bitmap
;
53 uint8_t s_prealloc_blocks
;
54 uint8_t s_prealloc_dir_blocks
;
55 uint16_t s_reserved_gdt_blocks
;
56 uint8_t s_journal_uuid
[16];
57 uint32_t s_journal_inum
;
58 uint32_t s_journal_dev
;
59 uint32_t s_last_orphan
;
60 uint32_t s_hash_seed
[4];
61 uint8_t s_def_hash_version
;
62 uint8_t s_jnl_backup_type
;
63 uint16_t s_reserved_word_pad
;
64 uint32_t s_default_mount_opts
;
65 uint32_t s_first_meta_bg
;
67 uint32_t s_jnl_blocks
[17];
68 uint32_t s_blocks_count_hi
;
69 uint32_t s_r_blocks_count_hi
;
70 uint32_t s_free_blocks_hi
;
71 uint16_t s_min_extra_isize
;
72 uint16_t s_want_extra_isize
;
74 uint16_t s_raid_stride
;
75 uint16_t s_mmp_interval
;
77 uint32_t s_raid_stripe_width
;
78 uint32_t s_reserved
[163];
79 } __attribute__((packed
));
82 #define EXT_SB_MAGIC "\123\357"
83 /* supper block offset */
84 #define EXT_SB_OFF 0x400
85 /* supper block offset in kB */
86 #define EXT_SB_KBOFF (EXT_SB_OFF >> 10)
87 /* magic string offset within super block */
88 #define EXT_MAG_OFF 0x38
93 #define EXT2_FLAGS_TEST_FILESYS 0x0004
95 /* for s_feature_compat */
96 #define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
98 /* for s_feature_ro_compat */
99 #define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
100 #define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
101 #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
102 #define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008
103 #define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
104 #define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
105 #define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
107 /* for s_feature_incompat */
108 #define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
109 #define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004
110 #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008
111 #define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
112 #define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */
113 #define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
114 #define EXT4_FEATURE_INCOMPAT_MMP 0x0100
115 #define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
117 #define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
118 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
119 EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
120 #define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
121 EXT2_FEATURE_INCOMPAT_META_BG)
122 #define EXT2_FEATURE_INCOMPAT_UNSUPPORTED ~EXT2_FEATURE_INCOMPAT_SUPP
123 #define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT2_FEATURE_RO_COMPAT_SUPP
125 #define EXT3_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
126 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
127 EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
128 #define EXT3_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
129 EXT3_FEATURE_INCOMPAT_RECOVER| \
130 EXT2_FEATURE_INCOMPAT_META_BG)
131 #define EXT3_FEATURE_INCOMPAT_UNSUPPORTED ~EXT3_FEATURE_INCOMPAT_SUPP
132 #define EXT3_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT3_FEATURE_RO_COMPAT_SUPP
135 * Check to see if a filesystem is in /proc/filesystems.
136 * Returns 1 if found, 0 if not
138 static int fs_proc_check(const char *fs_name
)
141 char buf
[80], *cp
, *t
;
143 f
= fopen("/proc/filesystems", "r");
147 if (!fgets(buf
, sizeof(buf
), f
))
151 while (*cp
&& !isspace(*cp
))
154 while (*cp
&& isspace(*cp
))
156 if ((t
= strchr(cp
, '\n')) != NULL
)
158 if ((t
= strchr(cp
, '\t')) != NULL
)
160 if ((t
= strchr(cp
, ' ')) != NULL
)
162 if (!strcmp(fs_name
, cp
)) {
172 * Check to see if a filesystem is available as a module
173 * Returns 1 if found, 0 if not
175 static int check_for_modules(const char *fs_name
)
185 snprintf(buf
, sizeof(buf
), "/lib/modules/%s/modules.dep", uts
.release
);
191 namesz
= strlen(fs_name
);
194 if (!fgets(buf
, sizeof(buf
), f
))
196 if ((cp
= strchr(buf
, ':')) != NULL
)
200 if ((cp
= strrchr(buf
, '/')) == NULL
)
204 if (!strncmp(cp
, fs_name
, namesz
) &&
205 (!strcmp(cp
+ namesz
, ".ko") ||
206 !strcmp(cp
+ namesz
, ".ko.gz"))) {
212 #endif /* __linux__ */
217 * Starting in 2.6.29, ext4 can be used to support filesystems
220 #define EXT4_SUPPORTS_EXT2 KERNEL_VERSION(2, 6, 29)
222 static int system_supports_ext2(void)
224 static time_t last_check
= 0;
226 time_t now
= time(0);
228 if (ret
!= -1 || (now
- last_check
) < 5)
231 ret
= (fs_proc_check("ext2") || check_for_modules("ext2"));
235 static int system_supports_ext4(void)
237 static time_t last_check
= 0;
239 time_t now
= time(0);
241 if (ret
!= -1 || (now
- last_check
) < 5)
244 ret
= (fs_proc_check("ext4") || check_for_modules("ext4"));
248 static int system_supports_ext4dev(void)
250 static time_t last_check
= 0;
252 time_t now
= time(0);
254 if (ret
!= -1 || (now
- last_check
) < 5)
257 ret
= (fs_proc_check("ext4dev") || check_for_modules("ext4dev"));
261 * reads superblock and returns:
262 * fc = feature_compat
263 * fi = feature_incompat
264 * frc = feature_ro_compat
266 static struct ext2_super_block
*ext_get_super(
267 blkid_probe pr
, uint32_t *fc
, uint32_t *fi
, uint32_t *frc
)
269 struct ext2_super_block
*es
;
271 es
= (struct ext2_super_block
*)
272 blkid_probe_get_buffer(pr
, EXT_SB_OFF
, 0x200);
276 *fc
= le32_to_cpu(es
->s_feature_compat
);
278 *fi
= le32_to_cpu(es
->s_feature_incompat
);
280 *frc
= le32_to_cpu(es
->s_feature_ro_compat
);
285 static void ext_get_info(blkid_probe pr
, int ver
, struct ext2_super_block
*es
)
287 //struct blkid_chain *chn = blkid_probe_get_chain(pr);
289 DBG(DEBUG_PROBE
, printf("ext2_sb.compat = %08X:%08X:%08X\n",
290 le32_to_cpu(es
->s_feature_compat
),
291 le32_to_cpu(es
->s_feature_incompat
),
292 le32_to_cpu(es
->s_feature_ro_compat
)));
294 if (strlen(es
->s_volume_name
))
295 blkid_probe_set_label(pr
, (unsigned char *) es
->s_volume_name
,
296 sizeof(es
->s_volume_name
));
297 blkid_probe_set_uuid(pr
, es
->s_uuid
);
299 if (le32_to_cpu(es
->s_feature_compat
) & EXT3_FEATURE_COMPAT_HAS_JOURNAL
)
300 blkid_probe_set_uuid_as(pr
, es
->s_journal_uuid
, "EXT_JOURNAL");
302 /* if (ver != 2 && (chn->flags & BLKID_SUBLKS_SECTYPE) &&
303 ((le32_to_cpu(es->s_feature_incompat) & EXT2_FEATURE_INCOMPAT_UNSUPPORTED) == 0))
304 blkid_probe_set_value(pr, "SEC_TYPE",
305 (unsigned char *) "ext2",
308 blkid_probe_sprintf_version(pr
, "%u.%u",
309 le32_to_cpu(es
->s_rev_level
),
310 le16_to_cpu(es
->s_minor_rev_level
));
314 static int probe_jbd(blkid_probe pr
,
315 const struct blkid_idmag
*mag
__attribute__((__unused__
)))
317 struct ext2_super_block
*es
;
320 es
= ext_get_super(pr
, NULL
, &fi
, NULL
);
322 return -BLKID_ERR_PARAM
;
323 if (!(fi
& EXT3_FEATURE_INCOMPAT_JOURNAL_DEV
))
324 return -BLKID_ERR_PARAM
;
326 ext_get_info(pr
, 2, es
);
330 static int probe_ext2(blkid_probe pr
,
331 const struct blkid_idmag
*mag
__attribute__((__unused__
)))
333 struct ext2_super_block
*es
;
334 uint32_t fc
, frc
, fi
;
336 es
= ext_get_super(pr
, &fc
, &fi
, &frc
);
338 return -BLKID_ERR_PARAM
;
340 /* Distinguish between ext3 and ext2 */
341 if (fc
& EXT3_FEATURE_COMPAT_HAS_JOURNAL
)
342 return -BLKID_ERR_PARAM
;
344 /* Any features which ext2 doesn't understand */
345 if ((frc
& EXT2_FEATURE_RO_COMPAT_UNSUPPORTED
) ||
346 (fi
& EXT2_FEATURE_INCOMPAT_UNSUPPORTED
))
347 return -BLKID_ERR_PARAM
;
350 * If ext2 is not present, but ext4 or ext4dev are, then
351 * disclaim we are ext2
353 if (!system_supports_ext2() &&
354 (system_supports_ext4() || system_supports_ext4dev()) &&
355 get_linux_version() >= EXT4_SUPPORTS_EXT2
)
356 return -BLKID_ERR_PARAM
;
358 ext_get_info(pr
, 2, es
);
362 static int probe_ext3(blkid_probe pr
,
363 const struct blkid_idmag
*mag
__attribute__((__unused__
)))
365 struct ext2_super_block
*es
;
366 uint32_t fc
, frc
, fi
;
368 es
= ext_get_super(pr
, &fc
, &fi
, &frc
);
370 return -BLKID_ERR_PARAM
;
372 /* ext3 requires journal */
373 if (!(fc
& EXT3_FEATURE_COMPAT_HAS_JOURNAL
))
374 return -BLKID_ERR_PARAM
;
376 /* Any features which ext3 doesn't understand */
377 if ((frc
& EXT3_FEATURE_RO_COMPAT_UNSUPPORTED
) ||
378 (fi
& EXT3_FEATURE_INCOMPAT_UNSUPPORTED
))
379 return -BLKID_ERR_PARAM
;
381 ext_get_info(pr
, 3, es
);
386 static int probe_ext4dev(blkid_probe pr
,
387 const struct blkid_idmag
*mag
__attribute__((__unused__
)))
389 struct ext2_super_block
*es
;
390 uint32_t fc
, frc
, fi
;
392 es
= ext_get_super(pr
, &fc
, &fi
, &frc
);
394 return -BLKID_ERR_PARAM
;
396 /* Distinguish from jbd */
397 if (fi
& EXT3_FEATURE_INCOMPAT_JOURNAL_DEV
)
398 return -BLKID_ERR_PARAM
;
401 * If the filesystem does not have a journal and ext2 and ext4
402 * is not present, then force this to be detected as an
403 * ext4dev filesystem.
405 if (!(fc
& EXT3_FEATURE_COMPAT_HAS_JOURNAL
) &&
406 !system_supports_ext2() && !system_supports_ext4() &&
407 system_supports_ext4dev() &&
408 get_linux_version() >= EXT4_SUPPORTS_EXT2
)
412 * If the filesystem is marked as OK for use by in-development
413 * filesystem code, but ext4dev is not supported, and ext4 is,
414 * then don't call ourselves ext4dev, since we should be
415 * detected as ext4 in that case.
417 * If the filesystem is marked as in use by production
418 * filesystem, then it can only be used by ext4 and NOT by
419 * ext4dev, so always disclaim we are ext4dev in that case.
421 if (le32_to_cpu(es
->s_flags
) & EXT2_FLAGS_TEST_FILESYS
) {
422 if (!system_supports_ext4dev() && system_supports_ext4())
423 return -BLKID_ERR_PARAM
;
425 return -BLKID_ERR_PARAM
;
428 ext_get_info(pr
, 4, es
);
432 static int probe_ext4(blkid_probe pr
,
433 const struct blkid_idmag
*mag
__attribute__((__unused__
)))
435 struct ext2_super_block
*es
;
436 uint32_t fc
, frc
, fi
;
438 es
= ext_get_super(pr
, &fc
, &fi
, &frc
);
442 /* Distinguish from jbd */
443 if (fi
& EXT3_FEATURE_INCOMPAT_JOURNAL_DEV
)
444 return -BLKID_ERR_PARAM
;
447 * If the filesystem does not have a journal and ext2 is not
448 * present, then force this to be detected as an ext2
451 if (!(fc
& EXT3_FEATURE_COMPAT_HAS_JOURNAL
) &&
452 !system_supports_ext2() && system_supports_ext4() &&
453 get_linux_version() >= EXT4_SUPPORTS_EXT2
)
456 /* Ext4 has at least one feature which ext3 doesn't understand */
457 if (!(frc
& EXT3_FEATURE_RO_COMPAT_UNSUPPORTED
) &&
458 !(fi
& EXT3_FEATURE_INCOMPAT_UNSUPPORTED
))
459 return -BLKID_ERR_PARAM
;
463 * If the filesystem is a OK for use by in-development
464 * filesystem code, and ext4dev is supported or ext4 is not
465 * supported, then don't call ourselves ext4, so we can redo
466 * the detection and mark the filesystem as ext4dev.
468 * If the filesystem is marked as in use by production
469 * filesystem, then it can only be used by ext4 and NOT by
472 if (le32_to_cpu(es
->s_flags
) & EXT2_FLAGS_TEST_FILESYS
) {
473 if (system_supports_ext4dev() || !system_supports_ext4())
474 return -BLKID_ERR_PARAM
;
477 ext_get_info(pr
, 4, es
);
481 #define BLKID_EXT_MAGICS \
484 .magic = EXT_SB_MAGIC, \
485 .len = sizeof(EXT_SB_MAGIC) - 1, \
486 .kboff = EXT_SB_KBOFF, \
487 .sboff = EXT_MAG_OFF \
492 const struct blkid_idinfo jbd_idinfo
=
495 .usage
= BLKID_USAGE_OTHER
,
496 .probefunc
= probe_jbd
,
497 .magics
= BLKID_EXT_MAGICS
500 const struct blkid_idinfo ext2_idinfo
=
503 .usage
= BLKID_USAGE_FILESYSTEM
,
504 .probefunc
= probe_ext2
,
505 .magics
= BLKID_EXT_MAGICS
508 const struct blkid_idinfo ext3_idinfo
=
511 .usage
= BLKID_USAGE_FILESYSTEM
,
512 .probefunc
= probe_ext3
,
513 .magics
= BLKID_EXT_MAGICS
516 const struct blkid_idinfo ext4_idinfo
=
519 .usage
= BLKID_USAGE_FILESYSTEM
,
520 .probefunc
= probe_ext4
,
521 .magics
= BLKID_EXT_MAGICS
524 const struct blkid_idinfo ext4dev_idinfo
=
527 .usage
= BLKID_USAGE_FILESYSTEM
,
528 .probefunc
= probe_ext4dev
,
529 .magics
= BLKID_EXT_MAGICS