blob: 5b1d179f36cbc31ab104077c178e27b8958f7bfa [file] [log] [blame]
bigbiff bigbiffe60683a2013-02-22 20:55:50 -05001/*
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>
5 *
6 * This file may be redistributed under the terms of the
7 * GNU Lesser General Public License.
8 */
9#include <stdio.h>
10#include <stdlib.h>
11#include <unistd.h>
12#include <string.h>
13#include <errno.h>
14#include <ctype.h>
15#include <stdint.h>
16#ifdef __linux__
17#include <sys/utsname.h>
18#endif
19#include <time.h>
20
bigbiff bigbiffe60683a2013-02-22 20:55:50 -050021#include "superblocks.h"
22
23struct ext2_super_block {
24 uint32_t s_inodes_count;
25 uint32_t s_blocks_count;
26 uint32_t s_r_blocks_count;
27 uint32_t s_free_blocks_count;
28 uint32_t s_free_inodes_count;
29 uint32_t s_first_data_block;
30 uint32_t s_log_block_size;
31 uint32_t s_dummy3[7];
32 unsigned char s_magic[2];
33 uint16_t s_state;
34 uint16_t s_errors;
35 uint16_t s_minor_rev_level;
36 uint32_t s_lastcheck;
37 uint32_t s_checkinterval;
38 uint32_t s_creator_os;
39 uint32_t s_rev_level;
40 uint16_t s_def_resuid;
41 uint16_t s_def_resgid;
42 uint32_t s_first_ino;
43 uint16_t s_inode_size;
44 uint16_t s_block_group_nr;
45 uint32_t s_feature_compat;
46 uint32_t s_feature_incompat;
47 uint32_t s_feature_ro_compat;
48 unsigned char s_uuid[16];
49 char s_volume_name[16];
50 char s_last_mounted[64];
51 uint32_t s_algorithm_usage_bitmap;
52 uint8_t s_prealloc_blocks;
53 uint8_t s_prealloc_dir_blocks;
54 uint16_t s_reserved_gdt_blocks;
55 uint8_t s_journal_uuid[16];
56 uint32_t s_journal_inum;
57 uint32_t s_journal_dev;
58 uint32_t s_last_orphan;
59 uint32_t s_hash_seed[4];
60 uint8_t s_def_hash_version;
61 uint8_t s_jnl_backup_type;
62 uint16_t s_reserved_word_pad;
63 uint32_t s_default_mount_opts;
64 uint32_t s_first_meta_bg;
65 uint32_t s_mkfs_time;
66 uint32_t s_jnl_blocks[17];
67 uint32_t s_blocks_count_hi;
68 uint32_t s_r_blocks_count_hi;
69 uint32_t s_free_blocks_hi;
70 uint16_t s_min_extra_isize;
71 uint16_t s_want_extra_isize;
72 uint32_t s_flags;
73 uint16_t s_raid_stride;
74 uint16_t s_mmp_interval;
75 uint64_t s_mmp_block;
76 uint32_t s_raid_stripe_width;
77 uint32_t s_reserved[163];
78} __attribute__((packed));
79
80/* magic string */
81#define EXT_SB_MAGIC "\123\357"
82/* supper block offset */
83#define EXT_SB_OFF 0x400
84/* supper block offset in kB */
85#define EXT_SB_KBOFF (EXT_SB_OFF >> 10)
86/* magic string offset within super block */
87#define EXT_MAG_OFF 0x38
88
89
90
91/* for s_flags */
92#define EXT2_FLAGS_TEST_FILESYS 0x0004
93
94/* for s_feature_compat */
95#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
96
97/* for s_feature_ro_compat */
98#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
99#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
100#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
101#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008
102#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
103#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
104#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
105
106/* for s_feature_incompat */
107#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
108#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004
109#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008
110#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
111#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */
112#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
113#define EXT4_FEATURE_INCOMPAT_MMP 0x0100
114#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
115
116#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
117 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
118 EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
119#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
120 EXT2_FEATURE_INCOMPAT_META_BG)
121#define EXT2_FEATURE_INCOMPAT_UNSUPPORTED ~EXT2_FEATURE_INCOMPAT_SUPP
122#define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT2_FEATURE_RO_COMPAT_SUPP
123
124#define EXT3_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
125 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
126 EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
127#define EXT3_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
128 EXT3_FEATURE_INCOMPAT_RECOVER| \
129 EXT2_FEATURE_INCOMPAT_META_BG)
130#define EXT3_FEATURE_INCOMPAT_UNSUPPORTED ~EXT3_FEATURE_INCOMPAT_SUPP
131#define EXT3_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT3_FEATURE_RO_COMPAT_SUPP
132
133/*
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500134 * Starting in 2.6.29, ext4 can be used to support filesystems
135 * without a journal.
136 */
137#define EXT4_SUPPORTS_EXT2 KERNEL_VERSION(2, 6, 29)
138
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500139/*
140 * reads superblock and returns:
141 * fc = feature_compat
142 * fi = feature_incompat
143 * frc = feature_ro_compat
144 */
145static struct ext2_super_block *ext_get_super(
146 blkid_probe pr, uint32_t *fc, uint32_t *fi, uint32_t *frc)
147{
148 struct ext2_super_block *es;
149
150 es = (struct ext2_super_block *)
151 blkid_probe_get_buffer(pr, EXT_SB_OFF, 0x200);
152 if (!es)
153 return NULL;
154 if (fc)
155 *fc = le32_to_cpu(es->s_feature_compat);
156 if (fi)
157 *fi = le32_to_cpu(es->s_feature_incompat);
158 if (frc)
159 *frc = le32_to_cpu(es->s_feature_ro_compat);
160
161 return es;
162}
163
164static void ext_get_info(blkid_probe pr, int ver, struct ext2_super_block *es)
165{
166 struct blkid_chain *chn = blkid_probe_get_chain(pr);
167
bigbiff7b4c7a62015-01-01 19:44:14 -0500168 DBG(PROBE, ul_debug("ext2_sb.compat = %08X:%08X:%08X",
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500169 le32_to_cpu(es->s_feature_compat),
170 le32_to_cpu(es->s_feature_incompat),
171 le32_to_cpu(es->s_feature_ro_compat)));
172
173 if (strlen(es->s_volume_name))
174 blkid_probe_set_label(pr, (unsigned char *) es->s_volume_name,
175 sizeof(es->s_volume_name));
176 blkid_probe_set_uuid(pr, es->s_uuid);
177
178 if (le32_to_cpu(es->s_feature_compat) & EXT3_FEATURE_COMPAT_HAS_JOURNAL)
179 blkid_probe_set_uuid_as(pr, es->s_journal_uuid, "EXT_JOURNAL");
180
181 if (ver != 2 && (chn->flags & BLKID_SUBLKS_SECTYPE) &&
182 ((le32_to_cpu(es->s_feature_incompat) & EXT2_FEATURE_INCOMPAT_UNSUPPORTED) == 0))
183 blkid_probe_set_value(pr, "SEC_TYPE",
184 (unsigned char *) "ext2",
185 sizeof("ext2"));
186
187 blkid_probe_sprintf_version(pr, "%u.%u",
188 le32_to_cpu(es->s_rev_level),
189 le16_to_cpu(es->s_minor_rev_level));
190}
191
192
193static int probe_jbd(blkid_probe pr,
194 const struct blkid_idmag *mag __attribute__((__unused__)))
195{
196 struct ext2_super_block *es;
197 uint32_t fi;
198
199 es = ext_get_super(pr, NULL, &fi, NULL);
200 if (!es)
bigbiff7b4c7a62015-01-01 19:44:14 -0500201 return errno ? -errno : 1;
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500202 if (!(fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV))
bigbiff7b4c7a62015-01-01 19:44:14 -0500203 return 1;
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500204
205 ext_get_info(pr, 2, es);
bigbiff7b4c7a62015-01-01 19:44:14 -0500206 blkid_probe_set_uuid_as(pr, es->s_uuid, "LOGUUID");
207
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500208 return 0;
209}
210
211static int probe_ext2(blkid_probe pr,
212 const struct blkid_idmag *mag __attribute__((__unused__)))
213{
214 struct ext2_super_block *es;
215 uint32_t fc, frc, fi;
216
217 es = ext_get_super(pr, &fc, &fi, &frc);
218 if (!es)
bigbiff7b4c7a62015-01-01 19:44:14 -0500219 return errno ? -errno : 1;
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500220
221 /* Distinguish between ext3 and ext2 */
222 if (fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL)
bigbiff7b4c7a62015-01-01 19:44:14 -0500223 return 1;
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500224
225 /* Any features which ext2 doesn't understand */
226 if ((frc & EXT2_FEATURE_RO_COMPAT_UNSUPPORTED) ||
227 (fi & EXT2_FEATURE_INCOMPAT_UNSUPPORTED))
bigbiff7b4c7a62015-01-01 19:44:14 -0500228 return 1;
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500229
230 ext_get_info(pr, 2, es);
231 return 0;
232}
233
234static int probe_ext3(blkid_probe pr,
235 const struct blkid_idmag *mag __attribute__((__unused__)))
236{
237 struct ext2_super_block *es;
238 uint32_t fc, frc, fi;
239
240 es = ext_get_super(pr, &fc, &fi, &frc);
241 if (!es)
bigbiff7b4c7a62015-01-01 19:44:14 -0500242 return errno ? -errno : 1;
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500243
244 /* ext3 requires journal */
245 if (!(fc & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
bigbiff7b4c7a62015-01-01 19:44:14 -0500246 return 1;
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500247
248 /* Any features which ext3 doesn't understand */
249 if ((frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) ||
250 (fi & EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
bigbiff7b4c7a62015-01-01 19:44:14 -0500251 return 1;
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500252
253 ext_get_info(pr, 3, es);
254 return 0;
255}
256
257
258static int probe_ext4dev(blkid_probe pr,
259 const struct blkid_idmag *mag __attribute__((__unused__)))
260{
261 struct ext2_super_block *es;
262 uint32_t fc, frc, fi;
263
264 es = ext_get_super(pr, &fc, &fi, &frc);
265 if (!es)
bigbiff7b4c7a62015-01-01 19:44:14 -0500266 return errno ? -errno : 1;
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500267
268 /* Distinguish from jbd */
269 if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
bigbiff7b4c7a62015-01-01 19:44:14 -0500270 return 1;
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500271
bigbiff7b4c7a62015-01-01 19:44:14 -0500272 if (!(le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS))
273 return 1;
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500274
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500275 ext_get_info(pr, 4, es);
276 return 0;
277}
278
279static int probe_ext4(blkid_probe pr,
280 const struct blkid_idmag *mag __attribute__((__unused__)))
281{
282 struct ext2_super_block *es;
283 uint32_t fc, frc, fi;
284
285 es = ext_get_super(pr, &fc, &fi, &frc);
286 if (!es)
bigbiff7b4c7a62015-01-01 19:44:14 -0500287 return errno ? -errno : 1;
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500288
289 /* Distinguish from jbd */
290 if (fi & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
bigbiff7b4c7a62015-01-01 19:44:14 -0500291 return 1;
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500292
293 /* Ext4 has at least one feature which ext3 doesn't understand */
294 if (!(frc & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) &&
295 !(fi & EXT3_FEATURE_INCOMPAT_UNSUPPORTED))
bigbiff7b4c7a62015-01-01 19:44:14 -0500296 return 1;
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500297
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500298 /*
299 * If the filesystem is a OK for use by in-development
300 * filesystem code, and ext4dev is supported or ext4 is not
301 * supported, then don't call ourselves ext4, so we can redo
302 * the detection and mark the filesystem as ext4dev.
303 *
304 * If the filesystem is marked as in use by production
305 * filesystem, then it can only be used by ext4 and NOT by
306 * ext4dev.
307 */
bigbiff7b4c7a62015-01-01 19:44:14 -0500308 if (le32_to_cpu(es->s_flags) & EXT2_FLAGS_TEST_FILESYS)
309 return 1;
bigbiff bigbiffe60683a2013-02-22 20:55:50 -0500310
311 ext_get_info(pr, 4, es);
312 return 0;
313}
314
315#define BLKID_EXT_MAGICS \
316 { \
317 { \
318 .magic = EXT_SB_MAGIC, \
319 .len = sizeof(EXT_SB_MAGIC) - 1, \
320 .kboff = EXT_SB_KBOFF, \
321 .sboff = EXT_MAG_OFF \
322 }, \
323 { NULL } \
324 }
325
326const struct blkid_idinfo jbd_idinfo =
327{
328 .name = "jbd",
329 .usage = BLKID_USAGE_OTHER,
330 .probefunc = probe_jbd,
331 .magics = BLKID_EXT_MAGICS
332};
333
334const struct blkid_idinfo ext2_idinfo =
335{
336 .name = "ext2",
337 .usage = BLKID_USAGE_FILESYSTEM,
338 .probefunc = probe_ext2,
339 .magics = BLKID_EXT_MAGICS
340};
341
342const struct blkid_idinfo ext3_idinfo =
343{
344 .name = "ext3",
345 .usage = BLKID_USAGE_FILESYSTEM,
346 .probefunc = probe_ext3,
347 .magics = BLKID_EXT_MAGICS
348};
349
350const struct blkid_idinfo ext4_idinfo =
351{
352 .name = "ext4",
353 .usage = BLKID_USAGE_FILESYSTEM,
354 .probefunc = probe_ext4,
355 .magics = BLKID_EXT_MAGICS
356};
357
358const struct blkid_idinfo ext4dev_idinfo =
359{
360 .name = "ext4dev",
361 .usage = BLKID_USAGE_FILESYSTEM,
362 .probefunc = probe_ext4dev,
363 .magics = BLKID_EXT_MAGICS
364};
365