Annotation of /trunk/mkinitrd-magellan/klibc/usr/kinit/fstype/fstype.c
Parent Directory | Revision Log
Revision 532 -
(hide annotations)
(download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 8060 byte(s)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 8060 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd
1 | niro | 532 | /* |
2 | * by rmk | ||
3 | * | ||
4 | * Detect filesystem type (on stdin) and output strings for two | ||
5 | * environment variables: | ||
6 | * FSTYPE - filesystem type | ||
7 | * FSSIZE - filesystem size (if known) | ||
8 | * | ||
9 | * We currently detect the filesystems listed below in the struct | ||
10 | * "imagetype images" (in the order they are listed). | ||
11 | * | ||
12 | * MINIX, ext3 and Reiserfs bits are currently untested. | ||
13 | */ | ||
14 | |||
15 | #include <sys/types.h> | ||
16 | #include <stdio.h> | ||
17 | #include <string.h> | ||
18 | #include <unistd.h> | ||
19 | #include <fcntl.h> | ||
20 | #include <endian.h> | ||
21 | #include <netinet/in.h> | ||
22 | #include <sys/vfs.h> | ||
23 | |||
24 | #define cpu_to_be32(x) __cpu_to_be32(x) /* Needed by romfs_fs.h */ | ||
25 | |||
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 "xfs_sb.h" | ||
32 | #include "luks_fs.h" | ||
33 | #include "lvm2_sb.h" | ||
34 | #include "iso9660_sb.h" | ||
35 | |||
36 | /* | ||
37 | * Slightly cleaned up version of jfs_superblock to | ||
38 | * avoid pulling in other kernel header files. | ||
39 | */ | ||
40 | #include "jfs_superblock.h" | ||
41 | |||
42 | /* | ||
43 | * reiserfs_fs.h is too sick to include directly. | ||
44 | * Use a cleaned up version. | ||
45 | */ | ||
46 | #include "reiserfs_fs.h" | ||
47 | |||
48 | #include "fstype.h" | ||
49 | |||
50 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) | ||
51 | |||
52 | #define BLOCK_SIZE 1024 | ||
53 | |||
54 | /* Swap needs the definition of block size */ | ||
55 | #include "swap_fs.h" | ||
56 | |||
57 | static int gzip_image(const void *buf, unsigned long long *bytes) | ||
58 | { | ||
59 | const unsigned char *p = buf; | ||
60 | |||
61 | if (p[0] == 037 && (p[1] == 0213 || p[1] == 0236)) { | ||
62 | /* The length of a gzip stream can only be determined | ||
63 | by processing the whole stream */ | ||
64 | *bytes = 0ULL; | ||
65 | return 1; | ||
66 | } | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | static int cramfs_image(const void *buf, unsigned long long *bytes) | ||
71 | { | ||
72 | const struct cramfs_super *sb = (const struct cramfs_super *)buf; | ||
73 | |||
74 | if (sb->magic == CRAMFS_MAGIC) { | ||
75 | if (sb->flags & CRAMFS_FLAG_FSID_VERSION_2) | ||
76 | *bytes = (unsigned long long)sb->fsid.blocks << 10; | ||
77 | else | ||
78 | *bytes = 0; | ||
79 | return 1; | ||
80 | } | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int romfs_image(const void *buf, unsigned long long *bytes) | ||
85 | { | ||
86 | const struct romfs_super_block *sb = | ||
87 | (const struct romfs_super_block *)buf; | ||
88 | |||
89 | if (sb->word0 == ROMSB_WORD0 && sb->word1 == ROMSB_WORD1) { | ||
90 | *bytes = __be32_to_cpu(sb->size); | ||
91 | return 1; | ||
92 | } | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int minix_image(const void *buf, unsigned long long *bytes) | ||
97 | { | ||
98 | const struct minix_super_block *sb = | ||
99 | (const struct minix_super_block *)buf; | ||
100 | |||
101 | if (sb->s_magic == MINIX_SUPER_MAGIC || | ||
102 | sb->s_magic == MINIX_SUPER_MAGIC2) { | ||
103 | *bytes = (unsigned long long)sb->s_nzones | ||
104 | << (sb->s_log_zone_size + 10); | ||
105 | return 1; | ||
106 | } | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static int ext3_image(const void *buf, unsigned long long *bytes) | ||
111 | { | ||
112 | const struct ext3_super_block *sb = | ||
113 | (const struct ext3_super_block *)buf; | ||
114 | |||
115 | if (sb->s_magic == __cpu_to_le16(EXT2_SUPER_MAGIC) && | ||
116 | sb-> | ||
117 | s_feature_compat & __cpu_to_le32(EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { | ||
118 | *bytes = (unsigned long long)__le32_to_cpu(sb->s_blocks_count) | ||
119 | << (10 + __le32_to_cpu(sb->s_log_block_size)); | ||
120 | return 1; | ||
121 | } | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static int ext2_image(const void *buf, unsigned long long *bytes) | ||
126 | { | ||
127 | const struct ext2_super_block *sb = | ||
128 | (const struct ext2_super_block *)buf; | ||
129 | |||
130 | if (sb->s_magic == __cpu_to_le16(EXT2_SUPER_MAGIC)) { | ||
131 | *bytes = (unsigned long long)__le32_to_cpu(sb->s_blocks_count) | ||
132 | << (10 + __le32_to_cpu(sb->s_log_block_size)); | ||
133 | return 1; | ||
134 | } | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static int reiserfs_image(const void *buf, unsigned long long *bytes) | ||
139 | { | ||
140 | const struct reiserfs_super_block *sb = | ||
141 | (const struct reiserfs_super_block *)buf; | ||
142 | |||
143 | if (memcmp(REISERFS_MAGIC(sb), REISERFS_SUPER_MAGIC_STRING, | ||
144 | sizeof(REISERFS_SUPER_MAGIC_STRING) - 1) == 0 || | ||
145 | memcmp(REISERFS_MAGIC(sb), REISER2FS_SUPER_MAGIC_STRING, | ||
146 | sizeof(REISER2FS_SUPER_MAGIC_STRING) - 1) == 0 || | ||
147 | memcmp(REISERFS_MAGIC(sb), REISER2FS_JR_SUPER_MAGIC_STRING, | ||
148 | sizeof(REISER2FS_JR_SUPER_MAGIC_STRING) - 1) == 0) { | ||
149 | *bytes = (unsigned long long)REISERFS_BLOCK_COUNT(sb) * | ||
150 | REISERFS_BLOCKSIZE(sb); | ||
151 | return 1; | ||
152 | } | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static int xfs_image(const void *buf, unsigned long long *bytes) | ||
157 | { | ||
158 | const struct xfs_sb *sb = (const struct xfs_sb *)buf; | ||
159 | |||
160 | if (__be32_to_cpu(sb->sb_magicnum) == XFS_SB_MAGIC) { | ||
161 | *bytes = __be64_to_cpu(sb->sb_dblocks) * | ||
162 | __be32_to_cpu(sb->sb_blocksize); | ||
163 | return 1; | ||
164 | } | ||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static int jfs_image(const void *buf, unsigned long long *bytes) | ||
169 | { | ||
170 | const struct jfs_superblock *sb = (const struct jfs_superblock *)buf; | ||
171 | |||
172 | if (!memcmp(sb->s_magic, JFS_MAGIC, 4)) { | ||
173 | *bytes = __le32_to_cpu(sb->s_size); | ||
174 | return 1; | ||
175 | } | ||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static int luks_image(const void *buf, unsigned long long *blocks) | ||
180 | { | ||
181 | const struct luks_partition_header *lph = | ||
182 | (const struct luks_partition_header *)buf; | ||
183 | |||
184 | if (!memcmp(lph->magic, LUKS_MAGIC, LUKS_MAGIC_L)) { | ||
185 | /* FSSIZE is dictated by the underlying fs, not by LUKS */ | ||
186 | *blocks = 0; | ||
187 | return 1; | ||
188 | } | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static int swap_image(const void *buf, unsigned long long *blocks) | ||
193 | { | ||
194 | const struct swap_super_block *ssb = | ||
195 | (const struct swap_super_block *)buf; | ||
196 | |||
197 | if (!memcmp(ssb->magic, SWAP_MAGIC_1, SWAP_MAGIC_L) || | ||
198 | !memcmp(ssb->magic, SWAP_MAGIC_2, SWAP_MAGIC_L)) { | ||
199 | *blocks = 0; | ||
200 | return 1; | ||
201 | } | ||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static int suspend_image(const void *buf, unsigned long long *blocks) | ||
206 | { | ||
207 | const struct swap_super_block *ssb = | ||
208 | (const struct swap_super_block *)buf; | ||
209 | |||
210 | if (!memcmp(ssb->magic, SUSP_MAGIC_1, SUSP_MAGIC_L) || | ||
211 | !memcmp(ssb->magic, SUSP_MAGIC_2, SUSP_MAGIC_L) || | ||
212 | !memcmp(ssb->magic, SUSP_MAGIC_U, SUSP_MAGIC_L)) { | ||
213 | *blocks = 0; | ||
214 | return 1; | ||
215 | } | ||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static int lvm2_image(const void *buf, unsigned long long *blocks) | ||
220 | { | ||
221 | const struct lvm2_super_block *lsb; | ||
222 | int i; | ||
223 | |||
224 | /* We must check every 512 byte sector */ | ||
225 | for (i = 0; i < BLOCK_SIZE; i += 0x200) { | ||
226 | lsb = (const struct lvm2_super_block *)(buf + i); | ||
227 | |||
228 | if (!memcmp(lsb->magic, LVM2_MAGIC, LVM2_MAGIC_L) && | ||
229 | !memcmp(lsb->type, LVM2_TYPE, LVM2_TYPE_L)) { | ||
230 | /* This is just one of possibly many PV's */ | ||
231 | *blocks = 0; | ||
232 | return 1; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static int iso_image(const void *buf, unsigned long long *blocks) | ||
240 | { | ||
241 | const struct iso_volume_descriptor *isovd = | ||
242 | (const struct iso_volume_descriptor *)buf; | ||
243 | const struct iso_hs_volume_descriptor *isohsvd = | ||
244 | (const struct iso_hs_volume_descriptor *)buf; | ||
245 | |||
246 | if (!memcmp(isovd->id, ISO_MAGIC, ISO_MAGIC_L) || | ||
247 | !memcmp(isohsvd->id, ISO_HS_MAGIC, ISO_HS_MAGIC_L)) { | ||
248 | *blocks = 0; | ||
249 | return 1; | ||
250 | } | ||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | struct imagetype { | ||
255 | off_t block; | ||
256 | const char name[12]; | ||
257 | int (*identify) (const void *, unsigned long long *); | ||
258 | }; | ||
259 | |||
260 | /* | ||
261 | * Note: | ||
262 | * | ||
263 | * Minix test needs to come after ext3/ext2, since it's possible for | ||
264 | * ext3/ext2 to look like minix by pure random chance. | ||
265 | * | ||
266 | * LVM comes after all other filesystems since it's possible | ||
267 | * that an old lvm signature is left on the disk if pvremove | ||
268 | * is not used before creating the new fs. | ||
269 | * | ||
270 | * The same goes for LUKS as for LVM. | ||
271 | */ | ||
272 | static struct imagetype images[] = { | ||
273 | {0, "gzip", gzip_image}, | ||
274 | {0, "cramfs", cramfs_image}, | ||
275 | {0, "romfs", romfs_image}, | ||
276 | {0, "xfs", xfs_image}, | ||
277 | {1, "ext3", ext3_image}, | ||
278 | {1, "ext2", ext2_image}, | ||
279 | {1, "minix", minix_image}, | ||
280 | {8, "reiserfs", reiserfs_image}, | ||
281 | {64, "reiserfs", reiserfs_image}, | ||
282 | {32, "jfs", jfs_image}, | ||
283 | {32, "iso9660", iso_image}, | ||
284 | {0, "luks", luks_image}, | ||
285 | {0, "lvm2", lvm2_image}, | ||
286 | {1, "lvm2", lvm2_image}, | ||
287 | {-1, "swap", swap_image}, | ||
288 | {-1, "suspend", suspend_image}, | ||
289 | {0, "", NULL} | ||
290 | }; | ||
291 | |||
292 | int identify_fs(int fd, const char **fstype, | ||
293 | unsigned long long *bytes, off_t offset) | ||
294 | { | ||
295 | uint64_t buf[BLOCK_SIZE >> 3]; /* 64-bit worst case alignment */ | ||
296 | off_t cur_block = (off_t) - 1; | ||
297 | struct imagetype *ip; | ||
298 | int ret; | ||
299 | unsigned long long dummy; | ||
300 | |||
301 | if (!bytes) | ||
302 | bytes = &dummy; | ||
303 | |||
304 | *fstype = NULL; | ||
305 | *bytes = 0; | ||
306 | |||
307 | for (ip = images; ip->identify; ip++) { | ||
308 | /* Hack for swap, which apparently is dependent on page size */ | ||
309 | if (ip->block == -1) | ||
310 | ip->block = SWAP_OFFSET(); | ||
311 | |||
312 | if (cur_block != ip->block) { | ||
313 | /* | ||
314 | * Read block. | ||
315 | */ | ||
316 | cur_block = ip->block; | ||
317 | ret = pread(fd, buf, BLOCK_SIZE, | ||
318 | offset + cur_block * BLOCK_SIZE); | ||
319 | if (ret != BLOCK_SIZE) | ||
320 | return -1; /* error */ | ||
321 | } | ||
322 | |||
323 | if (ip->identify(buf, bytes)) { | ||
324 | *fstype = ip->name; | ||
325 | return 0; | ||
326 | } | ||
327 | } | ||
328 | |||
329 | return 1; /* Unknown filesystem */ | ||
330 | } |