Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 815 - (hide 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 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    
13     #include <sys/types.h>
14     #include <stdio.h>
15 niro 815 #include <ctype.h>
16 niro 532 #include <string.h>
17     #include <unistd.h>
18     #include <fcntl.h>
19     #include <endian.h>
20     #include <netinet/in.h>
21 niro 815 #include <sys/utsname.h>
22 niro 532 #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 niro 815 #include "squashfs_fs.h"
36     #include "gfs2_fs.h"
37     #include "ocfs2_fs.h"
38     #include "nilfs_fs.h"
39 niro 532
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 niro 815 #include "reiser4_fs.h"
52 niro 532
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 niro 815 /*
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 niro 532 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 niro 815 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 niro 532 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 niro 815 *bytes = __le64_to_cpu(sb->s_size) << __le16_to_cpu(sb->s_l2pbsize);
329 niro 532 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 niro 815 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 niro 532 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 niro 815 {0, "squashfs", squashfs_image},
488     {1, "ext4dev", ext4dev_image},
489     {1, "ext4", ext4_image},
490 niro 532 {1, "ext3", ext3_image},
491     {1, "ext2", ext2_image},
492     {1, "minix", minix_image},
493 niro 815 {1, "nilfs2", nilfs2_image},
494     {2, "ocfs2", ocfs2_image},
495 niro 532 {8, "reiserfs", reiserfs_image},
496     {64, "reiserfs", reiserfs_image},
497 niro 815 {64, "reiser4", reiser4_image},
498     {64, "gfs2", gfs2_image},
499 niro 532 {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     }