Magellan Linux

Contents of /trunk/mkinitrd-magellan/klibc/usr/kinit/fstype/fstype.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 815 - (show annotations) (download)
Fri Apr 24 18:32:46 2009 UTC (15 years ago) by niro
File MIME type: text/plain
File size: 13334 byte(s)
-updated to klibc-1.5.15
1 /*
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
13 #include <sys/types.h>
14 #include <stdio.h>
15 #include <ctype.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <endian.h>
20 #include <netinet/in.h>
21 #include <sys/utsname.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 #include "squashfs_fs.h"
36 #include "gfs2_fs.h"
37 #include "ocfs2_fs.h"
38 #include "nilfs_fs.h"
39
40 /*
41 * Slightly cleaned up version of jfs_superblock to
42 * avoid pulling in other kernel header files.
43 */
44 #include "jfs_superblock.h"
45
46 /*
47 * reiserfs_fs.h is too sick to include directly.
48 * Use a cleaned up version.
49 */
50 #include "reiserfs_fs.h"
51 #include "reiser4_fs.h"
52
53 #include "fstype.h"
54
55 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
56
57 #define BLOCK_SIZE 1024
58
59 /* Swap needs the definition of block size */
60 #include "swap_fs.h"
61
62 static int gzip_image(const void *buf, unsigned long long *bytes)
63 {
64 const unsigned char *p = buf;
65
66 if (p[0] == 037 && (p[1] == 0213 || p[1] == 0236)) {
67 /* The length of a gzip stream can only be determined
68 by processing the whole stream */
69 *bytes = 0ULL;
70 return 1;
71 }
72 return 0;
73 }
74
75 static int cramfs_image(const void *buf, unsigned long long *bytes)
76 {
77 const struct cramfs_super *sb = (const struct cramfs_super *)buf;
78
79 if (sb->magic == CRAMFS_MAGIC) {
80 if (sb->flags & CRAMFS_FLAG_FSID_VERSION_2)
81 *bytes = (unsigned long long)sb->fsid.blocks << 10;
82 else
83 *bytes = 0;
84 return 1;
85 }
86 return 0;
87 }
88
89 static int romfs_image(const void *buf, unsigned long long *bytes)
90 {
91 const struct romfs_super_block *sb =
92 (const struct romfs_super_block *)buf;
93
94 if (sb->word0 == ROMSB_WORD0 && sb->word1 == ROMSB_WORD1) {
95 *bytes = __be32_to_cpu(sb->size);
96 return 1;
97 }
98 return 0;
99 }
100
101 static int minix_image(const void *buf, unsigned long long *bytes)
102 {
103 const struct minix_super_block *sb =
104 (const struct minix_super_block *)buf;
105
106 if (sb->s_magic == MINIX_SUPER_MAGIC ||
107 sb->s_magic == MINIX_SUPER_MAGIC2) {
108 *bytes = (unsigned long long)sb->s_nzones
109 << (sb->s_log_zone_size + 10);
110 return 1;
111 }
112 return 0;
113 }
114
115 /*
116 * Check to see if a filesystem is in /proc/filesystems.
117 * Returns 1 if found, 0 if not
118 */
119 static int fs_proc_check(const char *fs_name)
120 {
121 FILE *f;
122 char buf[80], *cp, *t;
123
124 f = fopen("/proc/filesystems", "r");
125 if (!f)
126 return (0);
127 while (fgets(buf, sizeof(buf), f)) {
128 cp = buf;
129 if (!isspace(*cp)) {
130 while (*cp && !isspace(*cp))
131 cp++;
132 }
133 while (*cp && isspace(*cp))
134 cp++;
135 if ((t = strchr(cp, '\n')) != NULL)
136 *t = 0;
137 if ((t = strchr(cp, '\t')) != NULL)
138 *t = 0;
139 if ((t = strchr(cp, ' ')) != NULL)
140 *t = 0;
141 if (!strcmp(fs_name, cp)) {
142 fclose(f);
143 return (1);
144 }
145 }
146 fclose(f);
147 return (0);
148 }
149
150 /*
151 * Check to see if a filesystem is available as a module
152 * Returns 1 if found, 0 if not
153 */
154 static int check_for_modules(const char *fs_name)
155 {
156 struct utsname uts;
157 FILE *f;
158 char buf[1024], *cp, *t;
159 int i;
160
161 if (uname(&uts))
162 return (0);
163 snprintf(buf, sizeof(buf), "/lib/modules/%s/modules.dep", uts.release);
164
165 f = fopen(buf, "r");
166 if (!f)
167 return (0);
168 while (fgets(buf, sizeof(buf), f)) {
169 if ((cp = strchr(buf, ':')) != NULL)
170 *cp = 0;
171 else
172 continue;
173 if ((cp = strrchr(buf, '/')) != NULL)
174 cp++;
175 i = strlen(cp);
176 if (i > 3) {
177 t = cp + i - 3;
178 if (!strcmp(t, ".ko"))
179 *t = 0;
180 }
181 if (!strcmp(cp, fs_name)) {
182 fclose(f);
183 return (1);
184 }
185 }
186 fclose(f);
187 return (0);
188 }
189
190 static int base_ext4_image(const void *buf, unsigned long long *bytes,
191 int *test_fs)
192 {
193 const struct ext3_super_block *sb =
194 (const struct ext3_super_block *)buf;
195
196 if (sb->s_magic != __cpu_to_le16(EXT2_SUPER_MAGIC))
197 return 0;
198
199 /*
200 * For now, ext4 requires a journal -- but this may change
201 * soon if we get that patch from Google. :-)
202 */
203 if ((sb->s_feature_compat
204 & __cpu_to_le32(EXT3_FEATURE_COMPAT_HAS_JOURNAL)) == 0)
205 return 0;
206
207 /* There is at least one feature not supported by ext3 */
208 if ((sb->s_feature_incompat
209 & __cpu_to_le32(EXT3_FEATURE_INCOMPAT_UNSUPPORTED)) ||
210 (sb->s_feature_ro_compat
211 & __cpu_to_le32(EXT3_FEATURE_RO_COMPAT_UNSUPPORTED))) {
212 *bytes = (unsigned long long)__le32_to_cpu(sb->s_blocks_count)
213 << (10 + __le32_to_cpu(sb->s_log_block_size));
214 *test_fs = (sb->s_flags &
215 __cpu_to_le32(EXT2_FLAGS_TEST_FILESYS)) != 0;
216 return 1;
217 }
218 return 0;
219 }
220
221 static int ext4_image(const void *buf, unsigned long long *bytes)
222 {
223 int ret, test_fs, ext4dev_present, ext4_present;
224
225 ret = base_ext4_image(buf, bytes, &test_fs);
226 if (ret == 0)
227 return 0;
228 ext4dev_present = (fs_proc_check("ext4dev") ||
229 check_for_modules("ext4dev"));
230 ext4_present = (fs_proc_check("ext4") || check_for_modules("ext4"));
231 if ((test_fs || !ext4_present) && ext4dev_present)
232 return 0;
233 return 1;
234 }
235
236 static int ext4dev_image(const void *buf, unsigned long long *bytes)
237 {
238 int ret, test_fs, ext4dev_present, ext4_present;
239
240 ret = base_ext4_image(buf, bytes, &test_fs);
241 if (ret == 0)
242 return 0;
243 ext4dev_present = (fs_proc_check("ext4dev") ||
244 check_for_modules("ext4dev"));
245 ext4_present = (fs_proc_check("ext4") || check_for_modules("ext4"));
246 if ((!test_fs || !ext4dev_present) && ext4_present)
247 return 0;
248 return 1;
249 }
250
251 static int ext3_image(const void *buf, unsigned long long *bytes)
252 {
253 const struct ext3_super_block *sb =
254 (const struct ext3_super_block *)buf;
255
256 if (sb->s_magic == __cpu_to_le16(EXT2_SUPER_MAGIC) &&
257 sb->
258 s_feature_compat & __cpu_to_le32(EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
259 *bytes = (unsigned long long)__le32_to_cpu(sb->s_blocks_count)
260 << (10 + __le32_to_cpu(sb->s_log_block_size));
261 return 1;
262 }
263 return 0;
264 }
265
266 static int ext2_image(const void *buf, unsigned long long *bytes)
267 {
268 const struct ext2_super_block *sb =
269 (const struct ext2_super_block *)buf;
270
271 if (sb->s_magic == __cpu_to_le16(EXT2_SUPER_MAGIC)) {
272 *bytes = (unsigned long long)__le32_to_cpu(sb->s_blocks_count)
273 << (10 + __le32_to_cpu(sb->s_log_block_size));
274 return 1;
275 }
276 return 0;
277 }
278
279 static int reiserfs_image(const void *buf, unsigned long long *bytes)
280 {
281 const struct reiserfs_super_block *sb =
282 (const struct reiserfs_super_block *)buf;
283
284 if (memcmp(REISERFS_MAGIC(sb), REISERFS_SUPER_MAGIC_STRING,
285 sizeof(REISERFS_SUPER_MAGIC_STRING) - 1) == 0 ||
286 memcmp(REISERFS_MAGIC(sb), REISER2FS_SUPER_MAGIC_STRING,
287 sizeof(REISER2FS_SUPER_MAGIC_STRING) - 1) == 0 ||
288 memcmp(REISERFS_MAGIC(sb), REISER2FS_JR_SUPER_MAGIC_STRING,
289 sizeof(REISER2FS_JR_SUPER_MAGIC_STRING) - 1) == 0) {
290 *bytes = (unsigned long long)REISERFS_BLOCK_COUNT(sb) *
291 REISERFS_BLOCKSIZE(sb);
292 return 1;
293 }
294 return 0;
295 }
296
297 static int reiser4_image(const void *buf, unsigned long long *bytes)
298 {
299 const struct reiser4_master_sb *sb =
300 (const struct reiser4_master_sb *)buf;
301
302 if (memcmp(sb->ms_magic, REISER4_SUPER_MAGIC_STRING,
303 sizeof(REISER4_SUPER_MAGIC_STRING) - 1) == 0) {
304 *bytes = (unsigned long long) __le32_to_cpu(sb->ms_format) *
305 __le32_to_cpu(sb->ms_blksize);
306 return 1;
307 }
308 return 0;
309 }
310
311 static int xfs_image(const void *buf, unsigned long long *bytes)
312 {
313 const struct xfs_sb *sb = (const struct xfs_sb *)buf;
314
315 if (__be32_to_cpu(sb->sb_magicnum) == XFS_SB_MAGIC) {
316 *bytes = __be64_to_cpu(sb->sb_dblocks) *
317 __be32_to_cpu(sb->sb_blocksize);
318 return 1;
319 }
320 return 0;
321 }
322
323 static int jfs_image(const void *buf, unsigned long long *bytes)
324 {
325 const struct jfs_superblock *sb = (const struct jfs_superblock *)buf;
326
327 if (!memcmp(sb->s_magic, JFS_MAGIC, 4)) {
328 *bytes = __le64_to_cpu(sb->s_size) << __le16_to_cpu(sb->s_l2pbsize);
329 return 1;
330 }
331 return 0;
332 }
333
334 static int luks_image(const void *buf, unsigned long long *blocks)
335 {
336 const struct luks_partition_header *lph =
337 (const struct luks_partition_header *)buf;
338
339 if (!memcmp(lph->magic, LUKS_MAGIC, LUKS_MAGIC_L)) {
340 /* FSSIZE is dictated by the underlying fs, not by LUKS */
341 *blocks = 0;
342 return 1;
343 }
344 return 0;
345 }
346
347 static int swap_image(const void *buf, unsigned long long *blocks)
348 {
349 const struct swap_super_block *ssb =
350 (const struct swap_super_block *)buf;
351
352 if (!memcmp(ssb->magic, SWAP_MAGIC_1, SWAP_MAGIC_L) ||
353 !memcmp(ssb->magic, SWAP_MAGIC_2, SWAP_MAGIC_L)) {
354 *blocks = 0;
355 return 1;
356 }
357 return 0;
358 }
359
360 static int suspend_image(const void *buf, unsigned long long *blocks)
361 {
362 const struct swap_super_block *ssb =
363 (const struct swap_super_block *)buf;
364
365 if (!memcmp(ssb->magic, SUSP_MAGIC_1, SUSP_MAGIC_L) ||
366 !memcmp(ssb->magic, SUSP_MAGIC_2, SUSP_MAGIC_L) ||
367 !memcmp(ssb->magic, SUSP_MAGIC_U, SUSP_MAGIC_L)) {
368 *blocks = 0;
369 return 1;
370 }
371 return 0;
372 }
373
374 static int lvm2_image(const void *buf, unsigned long long *blocks)
375 {
376 const struct lvm2_super_block *lsb;
377 int i;
378
379 /* We must check every 512 byte sector */
380 for (i = 0; i < BLOCK_SIZE; i += 0x200) {
381 lsb = (const struct lvm2_super_block *)(buf + i);
382
383 if (!memcmp(lsb->magic, LVM2_MAGIC, LVM2_MAGIC_L) &&
384 !memcmp(lsb->type, LVM2_TYPE, LVM2_TYPE_L)) {
385 /* This is just one of possibly many PV's */
386 *blocks = 0;
387 return 1;
388 }
389 }
390
391 return 0;
392 }
393
394 static int iso_image(const void *buf, unsigned long long *blocks)
395 {
396 const struct iso_volume_descriptor *isovd =
397 (const struct iso_volume_descriptor *)buf;
398 const struct iso_hs_volume_descriptor *isohsvd =
399 (const struct iso_hs_volume_descriptor *)buf;
400
401 if (!memcmp(isovd->id, ISO_MAGIC, ISO_MAGIC_L) ||
402 !memcmp(isohsvd->id, ISO_HS_MAGIC, ISO_HS_MAGIC_L)) {
403 *blocks = 0;
404 return 1;
405 }
406 return 0;
407 }
408
409 static int squashfs_image(const void *buf, unsigned long long *blocks)
410 {
411 const struct squashfs_super_block *sb =
412 (const struct squashfs_super_block *)buf;
413
414 if (sb->s_magic == SQUASHFS_MAGIC
415 || sb->s_magic == SQUASHFS_MAGIC_SWAP
416 || sb->s_magic == SQUASHFS_MAGIC_LZMA
417 || sb->s_magic == SQUASHFS_MAGIC_LZMA_SWAP) {
418 *blocks = (unsigned long long) sb->bytes_used;
419 return 1;
420 }
421 return 0;
422 }
423
424 static int gfs2_image(const void *buf, unsigned long long *bytes)
425 {
426 const struct gfs2_sb *sb =
427 (const struct gfs2_sb *)buf;
428
429 if (__be32_to_cpu(sb->sb_header.mh_magic) == GFS2_MAGIC
430 && (__be32_to_cpu(sb->sb_fs_format) == GFS2_FORMAT_FS
431 || __be32_to_cpu(sb->sb_fs_format) == GFS2_FORMAT_MULTI)) {
432 *bytes = 0; /* cpu_to_be32(sb->sb_bsize) * ?; */
433 return 1;
434 }
435 return 0;
436 }
437
438 static int ocfs2_image(const void *buf, unsigned long long *bytes)
439 {
440 const struct ocfs2_dinode *sb =
441 (const struct ocfs2_dinode *)buf;
442
443 if (!memcmp(sb->i_signature, OCFS2_SUPER_BLOCK_SIGNATURE,
444 sizeof(OCFS2_SUPER_BLOCK_SIGNATURE) - 1)) {
445 *bytes = 0;
446 return 1;
447 }
448 return 0;
449 }
450
451 static int nilfs2_image(const void *buf, unsigned long long *bytes)
452 {
453 const struct nilfs_super_block *sb =
454 (const struct nilfs_super_block *)buf;
455
456 if (sb->s_magic == __cpu_to_le16(NILFS_SUPER_MAGIC) &&
457 sb->s_rev_level == __cpu_to_le32(2)) {
458 *bytes = (unsigned long long)__le64_to_cpu(sb->s_dev_size);
459 return 1;
460 }
461 return 0;
462 }
463
464 struct imagetype {
465 off_t block;
466 const char name[12];
467 int (*identify) (const void *, unsigned long long *);
468 };
469
470 /*
471 * Note:
472 *
473 * Minix test needs to come after ext3/ext2, since it's possible for
474 * ext3/ext2 to look like minix by pure random chance.
475 *
476 * LVM comes after all other filesystems since it's possible
477 * that an old lvm signature is left on the disk if pvremove
478 * is not used before creating the new fs.
479 *
480 * The same goes for LUKS as for LVM.
481 */
482 static struct imagetype images[] = {
483 {0, "gzip", gzip_image},
484 {0, "cramfs", cramfs_image},
485 {0, "romfs", romfs_image},
486 {0, "xfs", xfs_image},
487 {0, "squashfs", squashfs_image},
488 {1, "ext4dev", ext4dev_image},
489 {1, "ext4", ext4_image},
490 {1, "ext3", ext3_image},
491 {1, "ext2", ext2_image},
492 {1, "minix", minix_image},
493 {1, "nilfs2", nilfs2_image},
494 {2, "ocfs2", ocfs2_image},
495 {8, "reiserfs", reiserfs_image},
496 {64, "reiserfs", reiserfs_image},
497 {64, "reiser4", reiser4_image},
498 {64, "gfs2", gfs2_image},
499 {32, "jfs", jfs_image},
500 {32, "iso9660", iso_image},
501 {0, "luks", luks_image},
502 {0, "lvm2", lvm2_image},
503 {1, "lvm2", lvm2_image},
504 {-1, "swap", swap_image},
505 {-1, "suspend", suspend_image},
506 {0, "", NULL}
507 };
508
509 int identify_fs(int fd, const char **fstype,
510 unsigned long long *bytes, off_t offset)
511 {
512 uint64_t buf[BLOCK_SIZE >> 3]; /* 64-bit worst case alignment */
513 off_t cur_block = (off_t) - 1;
514 struct imagetype *ip;
515 int ret;
516 unsigned long long dummy;
517
518 if (!bytes)
519 bytes = &dummy;
520
521 *fstype = NULL;
522 *bytes = 0;
523
524 for (ip = images; ip->identify; ip++) {
525 /* Hack for swap, which apparently is dependent on page size */
526 if (ip->block == -1)
527 ip->block = SWAP_OFFSET();
528
529 if (cur_block != ip->block) {
530 /*
531 * Read block.
532 */
533 cur_block = ip->block;
534 ret = pread(fd, buf, BLOCK_SIZE,
535 offset + cur_block * BLOCK_SIZE);
536 if (ret != BLOCK_SIZE)
537 return -1; /* error */
538 }
539
540 if (ip->identify(buf, bytes)) {
541 *fstype = ip->name;
542 return 0;
543 }
544 }
545
546 return 1; /* Unknown filesystem */
547 }