1 /*
2 * Copyright (C) 1999 by Andries Brouwer
3 * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
4 * Copyright (C) 2001 by Andreas Dilger
5 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
6 * Copyright (C) 2008-2013 Karel Zak <kzak@redhat.com>
7 *
8 * This file may be redistributed under the terms of the
9 * GNU Lesser General Public License.
10 */
11
12 #include <string.h>
13 #include "superblocks.h"
14 #include "minix.h"
15
16 #define minix_swab16(doit, num) ((uint16_t) (doit ? swab16(num) : num))
17 #define minix_swab32(doit, num) ((uint32_t) (doit ? swab32(num) : num))
18
19 static int get_minix_version(const unsigned char *data, int *other_endian)
20 {
21 const struct minix_super_block *sb = (const struct minix_super_block *) data;
22 const struct minix3_super_block *sb3 = (const struct minix3_super_block *) data;
23 int version = 0;
24 char *endian;
25
26 *other_endian = 0;
27
28 switch (sb->s_magic) {
29 case MINIX_SUPER_MAGIC:
30 case MINIX_SUPER_MAGIC2:
31 version = 1;
32 break;
33 case MINIX2_SUPER_MAGIC:
34 case MINIX2_SUPER_MAGIC2:
35 version = 2;
36 break;
37 default:
38 if (sb3->s_magic == MINIX3_SUPER_MAGIC)
39 version = 3;
40 break;
41 }
42
43 if (!version) {
44 *other_endian = 1;
45
46 switch (swab16(sb->s_magic)) {
47 case MINIX_SUPER_MAGIC:
48 case MINIX_SUPER_MAGIC2:
49 version = 1;
50 break;
51 case MINIX2_SUPER_MAGIC:
52 case MINIX2_SUPER_MAGIC2:
53 version = 2;
54 break;
55 default:
56 if (sb3->s_magic == MINIX3_SUPER_MAGIC)
57 version = 3;
58 break;
59 }
60 }
61 if (!version)
62 return -1;
63
64 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
65 endian = *other_endian ? "LE" : "BE";
66 #else
67 endian = *other_endian ? "BE" : "LE";
68 #endif
69 DBG(LOWPROBE, ul_debug("minix version %d detected [%s]", version,
70 endian));
71 return version;
72 }
73
74 static int probe_minix(blkid_probe pr,
75 const struct blkid_idmag *mag __attribute__((__unused__)))
76 {
77 unsigned char *ext;
78 const unsigned char *data;
79 int version = 0, swabme = 0;
80 unsigned long zones, ninodes, imaps, zmaps;
81 off_t firstz;
82 size_t zone_size;
83 unsigned block_size;
84
85 data = blkid_probe_get_buffer(pr, 1024,
86 max(sizeof(struct minix_super_block),
87 sizeof(struct minix3_super_block)));
88 if (!data)
89 return errno ? -errno : 1;
90 version = get_minix_version(data, &swabme);
91 switch (version) {
92 case 1:
93 case 2: {
94 const struct minix_super_block *sb = (const struct minix_super_block *) data;
95
96 uint16_t state = minix_swab16(swabme, sb->s_state);
97 if ((state & (MINIX_VALID_FS | MINIX_ERROR_FS)) != state)
98 return 1;
99
100 zones = version == 2 ? minix_swab32(swabme, sb->s_zones) :
101 minix_swab16(swabme, sb->s_nzones);
102 ninodes = minix_swab16(swabme, sb->s_ninodes);
103 imaps = minix_swab16(swabme, sb->s_imap_blocks);
104 zmaps = minix_swab16(swabme, sb->s_zmap_blocks);
105 firstz = minix_swab16(swabme, sb->s_firstdatazone);
106 zone_size = sb->s_log_zone_size;
107 block_size = 1024;
108 break;
109 }
110 case 3: {
111 const struct minix3_super_block *sb = (const struct minix3_super_block *) data;
112
113 zones = minix_swab32(swabme, sb->s_zones);
114 ninodes = minix_swab32(swabme, sb->s_ninodes);
115 imaps = minix_swab16(swabme, sb->s_imap_blocks);
116 zmaps = minix_swab16(swabme, sb->s_zmap_blocks);
117 firstz = minix_swab16(swabme, sb->s_firstdatazone);
118 zone_size = sb->s_log_zone_size;
119 block_size = minix_swab16(swabme, sb->s_blocksize);
120
121 break;
122 }
123 default:
124 return 1;
125 }
126
127 /* sanity checks to be sure that the FS is really minix.
128 * see disk-utils/fsck.minix.c read_superblock
129 */
130 if (zone_size != 0 || ninodes == 0 || ninodes == UINT32_MAX)
131 return 1;
132 if (imaps * MINIX_BLOCK_SIZE * 8 < ninodes + 1)
133 return 1;
134 if (firstz > (off_t) zones)
135 return 1;
136 if (zmaps * MINIX_BLOCK_SIZE * 8 < zones - firstz + 1)
137 return 1;
138
139 /* unfortunately, some parts of ext3 is sometimes possible to
140 * interpreted as minix superblock. So check for extN magic
141 * string. (For extN magic string and offsets see ext.c.)
142 */
143 ext = blkid_probe_get_buffer(pr, 0x400 + 0x38, 2);
144 if (!ext)
145 return errno ? -errno : 1;
146
147 if (memcmp(ext, "\123\357", 2) == 0)
148 return 1;
149
150 blkid_probe_sprintf_version(pr, "%d", version);
151 blkid_probe_set_fsblocksize(pr, block_size);
152 blkid_probe_set_block_size(pr, block_size);
153 blkid_probe_set_fsendianness(pr, !swabme ?
154 BLKID_ENDIANNESS_NATIVE : BLKID_ENDIANNESS_OTHER);
155 return 0;
156 }
157
158 const struct blkid_idinfo minix_idinfo =
159 {
160 .name = "minix",
161 .usage = BLKID_USAGE_FILESYSTEM,
162 .probefunc = probe_minix,
163 .magics =
164 {
165 /* version 1 - LE */
166 { .magic = "\177\023", .len = 2, .kboff = 1, .sboff = 0x10 },
167 { .magic = "\217\023", .len = 2, .kboff = 1, .sboff = 0x10 },
168
169 /* version 1 - BE */
170 { .magic = "\023\177", .len = 2, .kboff = 1, .sboff = 0x10 },
171 { .magic = "\023\217", .len = 2, .kboff = 1, .sboff = 0x10 },
172
173 /* version 2 - LE */
174 { .magic = "\150\044", .len = 2, .kboff = 1, .sboff = 0x10 },
175 { .magic = "\170\044", .len = 2, .kboff = 1, .sboff = 0x10 },
176
177 /* version 2 - BE */
178 { .magic = "\044\150", .len = 2, .kboff = 1, .sboff = 0x10 },
179 { .magic = "\044\170", .len = 2, .kboff = 1, .sboff = 0x10 },
180
181 /* version 3 - LE */
182 { .magic = "\132\115", .len = 2, .kboff = 1, .sboff = 0x18 },
183
184 /* version 3 - BE */
185 { .magic = "\115\132", .len = 2, .kboff = 1, .sboff = 0x18 },
186
187 { NULL }
188 }
189 };
190