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, const struct blkid_idmag *mag)
316
struct ext2_super_block *es;
319
es = ext_get_super(pr, NULL, &fi, NULL);
321
return -BLKID_ERR_PARAM;
322
if (!(fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV))
323
return -BLKID_ERR_PARAM;
325
ext_get_info(pr, 2, es);
329
static int probe_ext2(blkid_probe pr, const struct blkid_idmag *mag)
331
struct ext2_super_block *es;
332
uint32_t fc, frc, fi;
334
es = ext_get_super(pr, &fc, &fi, &frc);
336
return -BLKID_ERR_PARAM;
338
/* Distinguish between ext3 and ext2 */
339
if (fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL)
340
return -BLKID_ERR_PARAM;
342
/* Any features which ext2 doesn't understand */
343
if ((frc & EXT2_FEATURE_RO_COMPAT_UNSUPPORTED) ||
344
(fi & EXT2_FEATURE_INCOMPAT_UNSUPPORTED))
345
return -BLKID_ERR_PARAM;
348
* If ext2 is not present, but ext4 or ext4dev are, then
349
* disclaim we are ext2
351
if (!system_supports_ext2() &&
352
(system_supports_ext4() || system_supports_ext4dev()) &&
353
get_linux_version() >= EXT4_SUPPORTS_EXT2)
354
return -BLKID_ERR_PARAM;
356
ext_get_info(pr, 2, es);
360
static int probe_ext3(blkid_probe pr, const struct blkid_idmag *mag)
362
struct ext2_super_block *es;
363
uint32_t fc, frc, fi;
365
es = ext_get_super(pr, &fc, &fi, &frc);
367
return -BLKID_ERR_PARAM;
369
/* ext3 requires journal */
370
if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
371
return -BLKID_ERR_PARAM;
373
/* Any features which ext3 doesn't understand */
374
if ((frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) ||
375
(fi & EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
376
return -BLKID_ERR_PARAM;
378
ext_get_info(pr, 3, es);
383
static int probe_ext4dev(blkid_probe pr, const struct blkid_idmag *mag)
385
struct ext2_super_block *es;
386
uint32_t fc, frc, fi;
388
es = ext_get_super(pr, &fc, &fi, &frc);
390
return -BLKID_ERR_PARAM;
392
/* Distinguish from jbd */
393
if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
394
return -BLKID_ERR_PARAM;
397
* If the filesystem does not have a journal and ext2 and ext4
398
* is not present, then force this to be detected as an
399
* ext4dev filesystem.
401
if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
402
!system_supports_ext2() && !system_supports_ext4() &&
403
system_supports_ext4dev() &&
404
get_linux_version() >= EXT4_SUPPORTS_EXT2)
408
* If the filesystem is marked as OK for use by in-development
409
* filesystem code, but ext4dev is not supported, and ext4 is,
410
* then don't call ourselves ext4dev, since we should be
411
* detected as ext4 in that case.
413
* If the filesystem is marked as in use by production
414
* filesystem, then it can only be used by ext4 and NOT by
415
* ext4dev, so always disclaim we are ext4dev in that case.
417
if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) {
418
if (!system_supports_ext4dev() && system_supports_ext4())
419
return -BLKID_ERR_PARAM;
421
return -BLKID_ERR_PARAM;
424
ext_get_info(pr, 4, es);
428
static int probe_ext4(blkid_probe pr, const struct blkid_idmag *mag)
430
struct ext2_super_block *es;
431
uint32_t fc, frc, fi;
433
es = ext_get_super(pr, &fc, &fi, &frc);
437
/* Distinguish from jbd */
438
if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
439
return -BLKID_ERR_PARAM;
442
* If the filesystem does not have a journal and ext2 is not
443
* present, then force this to be detected as an ext2
446
if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
447
!system_supports_ext2() && system_supports_ext4() &&
448
get_linux_version() >= EXT4_SUPPORTS_EXT2)
451
/* Ext4 has at least one feature which ext3 doesn't understand */
452
if (!(frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) &&
453
!(fi & EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
454
return -BLKID_ERR_PARAM;
458
* If the filesystem is a OK for use by in-development
459
* filesystem code, and ext4dev is supported or ext4 is not
460
* supported, then don't call ourselves ext4, so we can redo
461
* the detection and mark the filesystem as ext4dev.
463
* If the filesystem is marked as in use by production
464
* filesystem, then it can only be used by ext4 and NOT by
467
if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) {
468
if (system_supports_ext4dev() || !system_supports_ext4())
469
return -BLKID_ERR_PARAM;
472
ext_get_info(pr, 4, es);
476
#define BLKID_EXT_MAGICS \
479
.magic = EXT_SB_MAGIC, \
480
.len = sizeof(EXT_SB_MAGIC) - 1, \
481
.kboff = EXT_SB_KBOFF, \
482
.sboff = EXT_MAG_OFF \
487
const struct blkid_idinfo jbd_idinfo =
490
.usage = BLKID_USAGE_OTHER,
491
.probefunc = probe_jbd,
492
.magics = BLKID_EXT_MAGICS
495
const struct blkid_idinfo ext2_idinfo =
498
.usage = BLKID_USAGE_FILESYSTEM,
499
.probefunc = probe_ext2,
500
.magics = BLKID_EXT_MAGICS
503
const struct blkid_idinfo ext3_idinfo =
506
.usage = BLKID_USAGE_FILESYSTEM,
507
.probefunc = probe_ext3,
508
.magics = BLKID_EXT_MAGICS
511
const struct blkid_idinfo ext4_idinfo =
514
.usage = BLKID_USAGE_FILESYSTEM,
515
.probefunc = probe_ext4,
516
.magics = BLKID_EXT_MAGICS
519
const struct blkid_idinfo ext4dev_idinfo =
522
.usage = BLKID_USAGE_FILESYSTEM,
523
.probefunc = probe_ext4dev,
524
.magics = BLKID_EXT_MAGICS