]>
Commit | Line | Data |
---|---|---|
e12f2ae7 TT |
1 | /* |
2 | * probe.c - identify a block device by its contents, and return a dev | |
3 | * struct with the details | |
4 | * | |
5 | * Copyright (C) 1999 by Andries Brouwer | |
50b380b4 | 6 | * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o |
e12f2ae7 | 7 | * Copyright (C) 2001 by Andreas Dilger |
2f79e519 | 8 | * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> |
e12f2ae7 TT |
9 | * |
10 | * %Begin-Header% | |
11 | * This file may be redistributed under the terms of the | |
12 | * GNU Lesser General Public License. | |
13 | * %End-Header% | |
14 | */ | |
15 | ||
d1154eb4 | 16 | #include "config.h" |
e12f2ae7 TT |
17 | #include <stdio.h> |
18 | #include <string.h> | |
19 | #include <stdlib.h> | |
20 | #include <unistd.h> | |
21 | #include <fcntl.h> | |
3a538e42 | 22 | #include <ctype.h> |
e12f2ae7 TT |
23 | #include <sys/types.h> |
24 | #ifdef HAVE_SYS_STAT_H | |
25 | #include <sys/stat.h> | |
26 | #endif | |
27 | #ifdef HAVE_SYS_MKDEV_H | |
28 | #include <sys/mkdev.h> | |
29 | #endif | |
18f73430 | 30 | #ifdef __linux__ |
cfc19311 | 31 | #include <sys/utsname.h> |
18f73430 | 32 | #endif |
e12f2ae7 TT |
33 | #ifdef HAVE_ERRNO_H |
34 | #include <errno.h> | |
35 | #endif | |
7a603aa8 | 36 | #include "blkidP.h" |
e12f2ae7 TT |
37 | #include "uuid/uuid.h" |
38 | #include "probe.h" | |
39 | ||
45a3fa87 TT |
40 | static int figure_label_len(const unsigned char *label, int len) |
41 | { | |
42 | const unsigned char *end = label + len - 1; | |
43 | ||
44 | while ((*end == ' ' || *end == 0) && end >= label) | |
45 | --end; | |
871ad942 | 46 | if (end >= label) |
45a3fa87 | 47 | return end - label + 1; |
45a3fa87 TT |
48 | return 0; |
49 | } | |
50 | ||
efc6f628 | 51 | static unsigned char *get_buffer(struct blkid_probe *pr, |
cb0c5d70 | 52 | blkid_loff_t off, size_t len) |
ca749859 TT |
53 | { |
54 | ssize_t ret_read; | |
55 | unsigned char *newbuf; | |
56 | ||
57 | if (off + len <= SB_BUFFER_SIZE) { | |
58 | if (!pr->sbbuf) { | |
59 | pr->sbbuf = malloc(SB_BUFFER_SIZE); | |
60 | if (!pr->sbbuf) | |
61 | return NULL; | |
62 | if (lseek(pr->fd, 0, SEEK_SET) < 0) | |
63 | return NULL; | |
64 | ret_read = read(pr->fd, pr->sbbuf, SB_BUFFER_SIZE); | |
65 | if (ret_read < 0) | |
66 | ret_read = 0; | |
67 | pr->sb_valid = ret_read; | |
68 | } | |
69 | if (off+len > pr->sb_valid) | |
70 | return NULL; | |
71 | return pr->sbbuf + off; | |
72 | } else { | |
73 | if (len > pr->buf_max) { | |
74 | newbuf = realloc(pr->buf, len); | |
75 | if (newbuf == NULL) | |
76 | return NULL; | |
77 | pr->buf = newbuf; | |
78 | pr->buf_max = len; | |
79 | } | |
cb0c5d70 | 80 | if (blkid_llseek(pr->fd, off, SEEK_SET) < 0) |
ca749859 TT |
81 | return NULL; |
82 | ret_read = read(pr->fd, pr->buf, len); | |
83 | if (ret_read != (ssize_t) len) | |
84 | return NULL; | |
85 | return pr->buf; | |
86 | } | |
87 | } | |
88 | ||
89 | ||
e12f2ae7 | 90 | /* |
50b380b4 TT |
91 | * This is a special case code to check for an MDRAID device. We do |
92 | * this special since it requires checking for a superblock at the end | |
93 | * of the device. | |
e12f2ae7 | 94 | */ |
50b380b4 | 95 | static int check_mdraid(int fd, unsigned char *ret_uuid) |
e12f2ae7 | 96 | { |
50b380b4 TT |
97 | struct mdp_superblock_s *md; |
98 | blkid_loff_t offset; | |
99 | char buf[4096]; | |
efc6f628 | 100 | |
50b380b4 | 101 | if (fd < 0) |
e12f2ae7 TT |
102 | return -BLKID_ERR_PARAM; |
103 | ||
50b380b4 | 104 | offset = (blkid_get_dev_size(fd) & ~((blkid_loff_t)65535)) - 65536; |
e12f2ae7 TT |
105 | |
106 | if (blkid_llseek(fd, offset, 0) < 0 || | |
50b380b4 | 107 | read(fd, buf, 4096) != 4096) |
e12f2ae7 TT |
108 | return -BLKID_ERR_IO; |
109 | ||
50b380b4 | 110 | /* Check for magic number */ |
6b8be16e | 111 | if (memcmp("\251+N\374", buf, 4) && memcmp("\374N+\251", buf, 4)) |
e12f2ae7 TT |
112 | return -BLKID_ERR_PARAM; |
113 | ||
50b380b4 TT |
114 | if (!ret_uuid) |
115 | return 0; | |
116 | *ret_uuid = 0; | |
e12f2ae7 | 117 | |
50b380b4 TT |
118 | /* The MD UUID is not contiguous in the superblock, make it so */ |
119 | md = (struct mdp_superblock_s *)buf; | |
120 | if (md->set_uuid0 || md->set_uuid1 || md->set_uuid2 || md->set_uuid3) { | |
121 | memcpy(ret_uuid, &md->set_uuid0, 4); | |
c9105ffb | 122 | memcpy(ret_uuid + 4, &md->set_uuid1, 12); |
e12f2ae7 | 123 | } |
50b380b4 TT |
124 | return 0; |
125 | } | |
e12f2ae7 | 126 | |
d4e0b1c6 | 127 | static void set_uuid(blkid_dev dev, uuid_t uuid, const char *tag) |
50b380b4 TT |
128 | { |
129 | char str[37]; | |
e12f2ae7 | 130 | |
50b380b4 TT |
131 | if (!uuid_is_null(uuid)) { |
132 | uuid_unparse(uuid, str); | |
ba5e3849 | 133 | blkid_set_tag(dev, tag ? tag : "UUID", str, sizeof(str)); |
50b380b4 | 134 | } |
e12f2ae7 TT |
135 | } |
136 | ||
2921332f TT |
137 | static void get_ext2_info(blkid_dev dev, struct blkid_magic *id, |
138 | unsigned char *buf) | |
2e6a9feb TT |
139 | { |
140 | struct ext2_super_block *es = (struct ext2_super_block *) buf; | |
141 | const char *label = 0; | |
142 | ||
efc6f628 | 143 | DBG(DEBUG_PROBE, printf("ext2_sb.compat = %08X:%08X:%08X\n", |
2e6a9feb TT |
144 | blkid_le32(es->s_feature_compat), |
145 | blkid_le32(es->s_feature_incompat), | |
146 | blkid_le32(es->s_feature_ro_compat))); | |
147 | ||
7369f0ce | 148 | if (strlen(es->s_volume_name)) |
2e6a9feb | 149 | label = es->s_volume_name; |
7369f0ce | 150 | blkid_set_tag(dev, "LABEL", label, sizeof(es->s_volume_name)); |
2e6a9feb | 151 | |
ba5e3849 | 152 | set_uuid(dev, es->s_uuid, 0); |
2921332f TT |
153 | |
154 | if ((es->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && | |
155 | !uuid_is_null(es->s_journal_uuid)) | |
156 | set_uuid(dev, es->s_journal_uuid, "EXT_JOURNAL"); | |
157 | ||
158 | if (strcmp(id->bim_type, "ext2") && | |
159 | ((blkid_le32(es->s_feature_incompat) & | |
160 | EXT2_FEATURE_INCOMPAT_UNSUPPORTED) == 0)) | |
161 | blkid_set_tag(dev, "SEC_TYPE", "ext2", sizeof("ext2")); | |
2e6a9feb TT |
162 | } |
163 | ||
cfc19311 TT |
164 | /* |
165 | * Check to see if a filesystem is in /proc/filesystems. | |
166 | * Returns 1 if found, 0 if not | |
167 | */ | |
3a538e42 | 168 | static int fs_proc_check(const char *fs_name) |
cfc19311 TT |
169 | { |
170 | FILE *f; | |
171 | char buf[80], *cp, *t; | |
172 | ||
173 | f = fopen("/proc/filesystems", "r"); | |
174 | if (!f) | |
175 | return (0); | |
176 | while (!feof(f)) { | |
177 | if (!fgets(buf, sizeof(buf), f)) | |
178 | break; | |
179 | cp = buf; | |
180 | if (!isspace(*cp)) { | |
181 | while (*cp && !isspace(*cp)) | |
182 | cp++; | |
183 | } | |
184 | while (*cp && isspace(*cp)) | |
185 | cp++; | |
186 | if ((t = strchr(cp, '\n')) != NULL) | |
187 | *t = 0; | |
188 | if ((t = strchr(cp, '\t')) != NULL) | |
189 | *t = 0; | |
190 | if ((t = strchr(cp, ' ')) != NULL) | |
191 | *t = 0; | |
192 | if (!strcmp(fs_name, cp)) { | |
193 | fclose(f); | |
194 | return (1); | |
195 | } | |
196 | } | |
197 | fclose(f); | |
198 | return (0); | |
199 | } | |
200 | ||
201 | /* | |
202 | * Check to see if a filesystem is available as a module | |
203 | * Returns 1 if found, 0 if not | |
204 | */ | |
3a538e42 | 205 | static int check_for_modules(const char *fs_name) |
cfc19311 | 206 | { |
18f73430 | 207 | #ifdef __linux__ |
cfc19311 TT |
208 | struct utsname uts; |
209 | FILE *f; | |
249c962a KZ |
210 | char buf[1024], *cp; |
211 | int namesz; | |
cfc19311 TT |
212 | |
213 | if (uname(&uts)) | |
214 | return (0); | |
215 | snprintf(buf, sizeof(buf), "/lib/modules/%s/modules.dep", uts.release); | |
216 | ||
217 | f = fopen(buf, "r"); | |
218 | if (!f) | |
219 | return (0); | |
249c962a KZ |
220 | |
221 | namesz = strlen(fs_name); | |
222 | ||
cfc19311 TT |
223 | while (!feof(f)) { |
224 | if (!fgets(buf, sizeof(buf), f)) | |
225 | break; | |
226 | if ((cp = strchr(buf, ':')) != NULL) | |
227 | *cp = 0; | |
228 | else | |
229 | continue; | |
230 | if ((cp = strrchr(buf, '/')) != NULL) | |
231 | cp++; | |
f2fe5da3 ES |
232 | else |
233 | cp = buf; | |
249c962a KZ |
234 | if (!strncmp(cp, fs_name, namesz) && |
235 | (!strcmp(cp + namesz, ".ko") || | |
236 | !strcmp(cp + namesz, ".ko.gz"))) { | |
6964a177 | 237 | fclose(f); |
cfc19311 | 238 | return (1); |
6964a177 | 239 | } |
cfc19311 TT |
240 | } |
241 | fclose(f); | |
18f73430 | 242 | #endif |
cfc19311 TT |
243 | return (0); |
244 | } | |
245 | ||
d1da14b5 | 246 | static int linux_version_code(void) |
1361821e TT |
247 | { |
248 | #ifdef __linux__ | |
249 | struct utsname ut; | |
cf5301d7 | 250 | static int version_code = -1; |
1361821e TT |
251 | int major, minor, rev; |
252 | char *endptr; | |
253 | const char *cp; | |
254 | ||
255 | if (version_code > 0) | |
256 | return version_code; | |
257 | ||
258 | if (uname(&ut)) | |
259 | return 0; | |
260 | cp = ut.release; | |
261 | ||
262 | major = strtol(cp, &endptr, 10); | |
263 | if (cp == endptr || *endptr != '.') | |
264 | return 0; | |
265 | cp = endptr + 1; | |
266 | minor = strtol(cp, &endptr, 10); | |
267 | if (cp == endptr || *endptr != '.') | |
268 | return 0; | |
269 | cp = endptr + 1; | |
270 | rev = strtol(cp, &endptr, 10); | |
271 | if (cp == endptr) | |
272 | return 0; | |
273 | version_code = (((major * 256) + minor) * 256) + rev; | |
274 | return version_code; | |
275 | #else | |
276 | return 0; | |
277 | #endif | |
278 | } | |
279 | ||
280 | #define EXT4_SUPPORTS_EXT2 (2 * 65536 + 6*256 + 29) | |
281 | ||
282 | static int system_supports_ext2(void) | |
283 | { | |
284 | static time_t last_check = 0; | |
285 | static int ret = -1; | |
286 | time_t now = time(0); | |
287 | ||
288 | if (ret != -1 || (now - last_check) < 5) | |
289 | return ret; | |
290 | last_check = now; | |
291 | ret = (fs_proc_check("ext2") || check_for_modules("ext2")); | |
292 | return ret; | |
293 | } | |
294 | ||
3a538e42 | 295 | static int system_supports_ext4(void) |
cfc19311 TT |
296 | { |
297 | static time_t last_check = 0; | |
298 | static int ret = -1; | |
299 | time_t now = time(0); | |
300 | ||
18f73430 | 301 | if (ret != -1 || (now - last_check) < 5) |
cfc19311 TT |
302 | return ret; |
303 | last_check = now; | |
304 | ret = (fs_proc_check("ext4") || check_for_modules("ext4")); | |
305 | return ret; | |
306 | } | |
307 | ||
3a538e42 | 308 | static int system_supports_ext4dev(void) |
cfc19311 TT |
309 | { |
310 | static time_t last_check = 0; | |
311 | static int ret = -1; | |
312 | time_t now = time(0); | |
313 | ||
18f73430 | 314 | if (ret != -1 || (now - last_check) < 5) |
cfc19311 TT |
315 | return ret; |
316 | last_check = now; | |
317 | ret = (fs_proc_check("ext4dev") || check_for_modules("ext4dev")); | |
318 | return ret; | |
319 | } | |
320 | ||
2921332f TT |
321 | static int probe_ext4dev(struct blkid_probe *probe, |
322 | struct blkid_magic *id, | |
323 | unsigned char *buf) | |
324 | { | |
325 | struct ext2_super_block *es; | |
326 | es = (struct ext2_super_block *)buf; | |
327 | ||
2921332f TT |
328 | /* Distinguish from jbd */ |
329 | if (blkid_le32(es->s_feature_incompat) & | |
330 | EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) | |
331 | return -BLKID_ERR_PARAM; | |
332 | ||
1361821e TT |
333 | /* |
334 | * If the filesystem does not have a journal and ext2 and ext4 | |
335 | * is not present, then force this to be detected as an | |
336 | * ext4dev filesystem. | |
337 | */ | |
338 | if (!(blkid_le32(es->s_feature_compat) & | |
339 | EXT3_FEATURE_COMPAT_HAS_JOURNAL) && | |
340 | !system_supports_ext2() && !system_supports_ext4() && | |
341 | system_supports_ext4dev() && | |
342 | linux_version_code() >= EXT4_SUPPORTS_EXT2) | |
343 | goto force_ext4dev; | |
344 | ||
cfc19311 TT |
345 | /* |
346 | * If the filesystem is marked as OK for use by in-development | |
347 | * filesystem code, but ext4dev is not supported, and ext4 is, | |
348 | * then don't call ourselves ext4dev, since we should be | |
349 | * detected as ext4 in that case. | |
350 | * | |
351 | * If the filesystem is marked as in use by production | |
352 | * filesystem, then it can only be used by ext4 and NOT by | |
353 | * ext4dev, so always disclaim we are ext4dev in that case. | |
354 | */ | |
355 | if (blkid_le32(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) { | |
356 | if (!system_supports_ext4dev() && system_supports_ext4()) | |
357 | return -BLKID_ERR_PARAM; | |
358 | } else | |
359 | return -BLKID_ERR_PARAM; | |
360 | ||
1361821e | 361 | force_ext4dev: |
2921332f TT |
362 | get_ext2_info(probe->dev, id, buf); |
363 | return 0; | |
364 | } | |
365 | ||
366 | static int probe_ext4(struct blkid_probe *probe, struct blkid_magic *id, | |
12b3c8ec | 367 | unsigned char *buf) |
e12f2ae7 | 368 | { |
e12f2ae7 | 369 | struct ext2_super_block *es; |
e12f2ae7 TT |
370 | es = (struct ext2_super_block *)buf; |
371 | ||
2921332f | 372 | /* Distinguish from jbd */ |
efc6f628 | 373 | if (blkid_le32(es->s_feature_incompat) & |
2e6a9feb | 374 | EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) |
e12f2ae7 | 375 | return -BLKID_ERR_PARAM; |
e12f2ae7 | 376 | |
1361821e TT |
377 | /* |
378 | * If the filesystem does not have a journal and ext2 is not | |
379 | * present, then force this to be detected as an ext2 | |
380 | * filesystem. | |
381 | */ | |
382 | if (!(blkid_le32(es->s_feature_compat) & | |
383 | EXT3_FEATURE_COMPAT_HAS_JOURNAL) && | |
384 | !system_supports_ext2() && system_supports_ext4() && | |
385 | linux_version_code() >= EXT4_SUPPORTS_EXT2) | |
386 | goto force_ext4; | |
387 | ||
2921332f TT |
388 | /* Ext4 has at least one feature which ext3 doesn't understand */ |
389 | if (!(blkid_le32(es->s_feature_ro_compat) & | |
390 | EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) && | |
391 | !(blkid_le32(es->s_feature_incompat) & | |
392 | EXT3_FEATURE_INCOMPAT_UNSUPPORTED)) | |
393 | return -BLKID_ERR_PARAM; | |
e12f2ae7 | 394 | |
1361821e | 395 | force_ext4: |
cfc19311 TT |
396 | /* |
397 | * If the filesystem is a OK for use by in-development | |
398 | * filesystem code, and ext4dev is supported or ext4 is not | |
399 | * supported, then don't call ourselves ext4, so we can redo | |
400 | * the detection and mark the filesystem as ext4dev. | |
401 | * | |
402 | * If the filesystem is marked as in use by production | |
403 | * filesystem, then it can only be used by ext4 and NOT by | |
404 | * ext4dev. | |
405 | */ | |
406 | if (blkid_le32(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) { | |
407 | if (system_supports_ext4dev() || !system_supports_ext4()) | |
408 | return -BLKID_ERR_PARAM; | |
409 | } | |
2921332f TT |
410 | get_ext2_info(probe->dev, id, buf); |
411 | return 0; | |
412 | } | |
ba5e3849 | 413 | |
2921332f TT |
414 | static int probe_ext3(struct blkid_probe *probe, struct blkid_magic *id, |
415 | unsigned char *buf) | |
416 | { | |
417 | struct ext2_super_block *es; | |
418 | es = (struct ext2_super_block *)buf; | |
2e6a9feb | 419 | |
2921332f TT |
420 | /* ext3 requires journal */ |
421 | if (!(blkid_le32(es->s_feature_compat) & | |
422 | EXT3_FEATURE_COMPAT_HAS_JOURNAL)) | |
423 | return -BLKID_ERR_PARAM; | |
2e6a9feb | 424 | |
2921332f TT |
425 | /* Any features which ext3 doesn't understand */ |
426 | if ((blkid_le32(es->s_feature_ro_compat) & | |
427 | EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) || | |
428 | (blkid_le32(es->s_feature_incompat) & | |
429 | EXT3_FEATURE_INCOMPAT_UNSUPPORTED)) | |
430 | return -BLKID_ERR_PARAM; | |
431 | ||
432 | get_ext2_info(probe->dev, id, buf); | |
2e6a9feb TT |
433 | return 0; |
434 | } | |
435 | ||
2921332f | 436 | static int probe_ext2(struct blkid_probe *probe, struct blkid_magic *id, |
12b3c8ec | 437 | unsigned char *buf) |
2e6a9feb TT |
438 | { |
439 | struct ext2_super_block *es; | |
2e6a9feb TT |
440 | |
441 | es = (struct ext2_super_block *)buf; | |
442 | ||
05a6edf4 KZ |
443 | /* Distinguish between ext3 and ext2 */ |
444 | if ((blkid_le32(es->s_feature_compat) & | |
445 | EXT3_FEATURE_COMPAT_HAS_JOURNAL)) | |
446 | return -BLKID_ERR_PARAM; | |
2e6a9feb | 447 | |
2921332f TT |
448 | /* Any features which ext2 doesn't understand */ |
449 | if ((blkid_le32(es->s_feature_ro_compat) & | |
450 | EXT2_FEATURE_RO_COMPAT_UNSUPPORTED) || | |
451 | (blkid_le32(es->s_feature_incompat) & | |
452 | EXT2_FEATURE_INCOMPAT_UNSUPPORTED)) | |
453 | return -BLKID_ERR_PARAM; | |
79dd234a | 454 | |
1361821e TT |
455 | /* |
456 | * If ext2 is not present, but ext4 or ext4dev are, then | |
457 | * disclaim we are ext2 | |
458 | */ | |
459 | if (!system_supports_ext2() && | |
460 | (system_supports_ext4() || system_supports_ext4dev()) && | |
461 | linux_version_code() >= EXT4_SUPPORTS_EXT2) | |
462 | return -BLKID_ERR_PARAM; | |
463 | ||
2921332f | 464 | get_ext2_info(probe->dev, id, buf); |
e12f2ae7 TT |
465 | return 0; |
466 | } | |
467 | ||
2921332f | 468 | static int probe_jbd(struct blkid_probe *probe, struct blkid_magic *id, |
54434927 | 469 | unsigned char *buf) |
e12f2ae7 | 470 | { |
50b380b4 | 471 | struct ext2_super_block *es = (struct ext2_super_block *) buf; |
e12f2ae7 | 472 | |
76b07bb1 | 473 | if (!(blkid_le32(es->s_feature_incompat) & |
50b380b4 | 474 | EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) |
e12f2ae7 | 475 | return -BLKID_ERR_PARAM; |
e12f2ae7 | 476 | |
2921332f | 477 | get_ext2_info(probe->dev, id, buf); |
2e6a9feb TT |
478 | |
479 | return 0; | |
e12f2ae7 TT |
480 | } |
481 | ||
2f79e519 TT |
482 | #define FAT_ATTR_VOLUME_ID 0x08 |
483 | #define FAT_ATTR_DIR 0x10 | |
484 | #define FAT_ATTR_LONG_NAME 0x0f | |
485 | #define FAT_ATTR_MASK 0x3f | |
486 | #define FAT_ENTRY_FREE 0xe5 | |
487 | ||
d4e0b1c6 | 488 | static const char *no_name = "NO NAME "; |
2f79e519 TT |
489 | |
490 | static unsigned char *search_fat_label(struct vfat_dir_entry *dir, int count) | |
491 | { | |
12a829dc | 492 | int i; |
2f79e519 TT |
493 | |
494 | for (i = 0; i < count; i++) { | |
495 | if (dir[i].name[0] == 0x00) | |
496 | break; | |
efc6f628 | 497 | |
2f79e519 TT |
498 | if ((dir[i].name[0] == FAT_ENTRY_FREE) || |
499 | (dir[i].cluster_high != 0 || dir[i].cluster_low != 0) || | |
500 | ((dir[i].attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME)) | |
501 | continue; | |
502 | ||
efc6f628 | 503 | if ((dir[i].attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == |
2f79e519 TT |
504 | FAT_ATTR_VOLUME_ID) { |
505 | return dir[i].name; | |
506 | } | |
507 | } | |
508 | return 0; | |
509 | } | |
510 | ||
511 | /* FAT label extraction from the root directory taken from Kay | |
512 | * Sievers's volume_id library */ | |
ca749859 | 513 | static int probe_fat(struct blkid_probe *probe, |
efc6f628 | 514 | struct blkid_magic *id __BLKID_ATTR((unused)), |
54434927 | 515 | unsigned char *buf) |
e12f2ae7 | 516 | { |
038d2bed TT |
517 | struct vfat_super_block *vs = (struct vfat_super_block *) buf; |
518 | struct msdos_super_block *ms = (struct msdos_super_block *) buf; | |
2f79e519 | 519 | struct vfat_dir_entry *dir; |
e12f2ae7 | 520 | char serno[10]; |
94fa1108 | 521 | const unsigned char *label = 0, *vol_label = 0, *tmp; |
038d2bed | 522 | unsigned char *vol_serno; |
2f79e519 TT |
523 | int label_len = 0, maxloop = 100; |
524 | __u16 sector_size, dir_entries, reserved; | |
525 | __u32 sect_count, fat_size, dir_size, cluster_count, fat_length; | |
526 | __u32 buf_size, start_data_sect, next, root_start, root_dir_entries; | |
e12f2ae7 | 527 | |
038d2bed | 528 | /* sector size check */ |
aadac9b7 MA |
529 | tmp = (unsigned char *)&ms->ms_sector_size; |
530 | sector_size = tmp[0] + (tmp[1] << 8); | |
038d2bed TT |
531 | if (sector_size != 0x200 && sector_size != 0x400 && |
532 | sector_size != 0x800 && sector_size != 0x1000) | |
533 | return 1; | |
e12f2ae7 | 534 | |
aadac9b7 MA |
535 | tmp = (unsigned char *)&ms->ms_dir_entries; |
536 | dir_entries = tmp[0] + (tmp[1] << 8); | |
038d2bed | 537 | reserved = blkid_le16(ms->ms_reserved); |
aadac9b7 MA |
538 | tmp = (unsigned char *)&ms->ms_sectors; |
539 | sect_count = tmp[0] + (tmp[1] << 8); | |
038d2bed TT |
540 | if (sect_count == 0) |
541 | sect_count = blkid_le32(ms->ms_total_sect); | |
e12f2ae7 | 542 | |
038d2bed TT |
543 | fat_length = blkid_le16(ms->ms_fat_length); |
544 | if (fat_length == 0) | |
545 | fat_length = blkid_le32(vs->vs_fat32_length); | |
e12f2ae7 | 546 | |
038d2bed TT |
547 | fat_size = fat_length * ms->ms_fats; |
548 | dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) + | |
549 | (sector_size-1)) / sector_size; | |
e12f2ae7 | 550 | |
038d2bed | 551 | cluster_count = sect_count - (reserved + fat_size + dir_size); |
20c10a76 TT |
552 | if (ms->ms_cluster_size == 0) |
553 | return 1; | |
038d2bed | 554 | cluster_count /= ms->ms_cluster_size; |
e12f2ae7 | 555 | |
038d2bed TT |
556 | if (cluster_count > FAT32_MAX) |
557 | return 1; | |
558 | ||
559 | if (ms->ms_fat_length) { | |
2f79e519 TT |
560 | /* the label may be an attribute in the root directory */ |
561 | root_start = (reserved + fat_size) * sector_size; | |
efc6f628 | 562 | root_dir_entries = vs->vs_dir_entries[0] + |
2f79e519 TT |
563 | (vs->vs_dir_entries[1] << 8); |
564 | ||
565 | buf_size = root_dir_entries * sizeof(struct vfat_dir_entry); | |
efc6f628 | 566 | dir = (struct vfat_dir_entry *) get_buffer(probe, root_start, |
2f79e519 TT |
567 | buf_size); |
568 | if (dir) | |
569 | vol_label = search_fat_label(dir, root_dir_entries); | |
570 | ||
571 | if (!vol_label || !memcmp(vol_label, no_name, 11)) | |
572 | vol_label = ms->ms_label; | |
038d2bed TT |
573 | vol_serno = ms->ms_serno; |
574 | ||
efc6f628 | 575 | blkid_set_tag(probe->dev, "SEC_TYPE", "msdos", |
2f79e519 | 576 | sizeof("msdos")); |
038d2bed | 577 | } else { |
2f79e519 TT |
578 | /* Search the FAT32 root dir for the label attribute */ |
579 | buf_size = vs->vs_cluster_size * sector_size; | |
580 | start_data_sect = reserved + fat_size; | |
581 | ||
582 | next = blkid_le32(vs->vs_root_cluster); | |
583 | while (next && --maxloop) { | |
584 | __u32 next_sect_off; | |
585 | __u64 next_off, fat_entry_off; | |
586 | int count; | |
587 | ||
a8307ab8 TT |
588 | next_sect_off = (next - 2) * vs->vs_cluster_size; |
589 | next_off = (__u64) (start_data_sect + next_sect_off) * | |
2f79e519 TT |
590 | sector_size; |
591 | ||
efc6f628 | 592 | dir = (struct vfat_dir_entry *) |
2f79e519 TT |
593 | get_buffer(probe, next_off, buf_size); |
594 | if (dir == NULL) | |
595 | break; | |
596 | ||
597 | count = buf_size / sizeof(struct vfat_dir_entry); | |
598 | ||
599 | vol_label = search_fat_label(dir, count); | |
600 | if (vol_label) | |
601 | break; | |
602 | ||
603 | /* get FAT entry */ | |
d1da14b5 TT |
604 | fat_entry_off = |
605 | ((unsigned int) reserved * | |
606 | (unsigned int) sector_size) + | |
2f79e519 TT |
607 | (next * sizeof(__u32)); |
608 | buf = get_buffer(probe, fat_entry_off, buf_size); | |
609 | if (buf == NULL) | |
610 | break; | |
611 | ||
612 | /* set next cluster */ | |
613 | next = blkid_le32(*((__u32 *) buf) & 0x0fffffff); | |
614 | } | |
615 | ||
616 | if (!vol_label || !memcmp(vol_label, no_name, 11)) | |
617 | vol_label = vs->vs_label; | |
038d2bed TT |
618 | vol_serno = vs->vs_serno; |
619 | } | |
e12f2ae7 | 620 | |
2f79e519 | 621 | if (vol_label && memcmp(vol_label, no_name, 11)) { |
633f453d KZ |
622 | if ((label_len = figure_label_len(vol_label, 11))) |
623 | label = vol_label; | |
e12f2ae7 TT |
624 | } |
625 | ||
626 | /* We can't just print them as %04X, because they are unaligned */ | |
038d2bed TT |
627 | sprintf(serno, "%02X%02X-%02X%02X", vol_serno[3], vol_serno[2], |
628 | vol_serno[1], vol_serno[0]); | |
629 | ||
ca749859 TT |
630 | blkid_set_tag(probe->dev, "LABEL", (const char *) label, label_len); |
631 | blkid_set_tag(probe->dev, "UUID", serno, sizeof(serno)-1); | |
e12f2ae7 TT |
632 | |
633 | return 0; | |
634 | } | |
635 | ||
c4c740ff KZ |
636 | /* |
637 | * The FAT filesystem could be without a magic string in superblock | |
638 | * (e.g. old floppies). This heuristic for FAT detection is inspired | |
639 | * by http://vrfy.org/projects/volume_id/ and Linux kernel. | |
640 | * [7-Jul-2005, Karel Zak <kzak@redhat.com>] | |
641 | */ | |
ca749859 | 642 | static int probe_fat_nomagic(struct blkid_probe *probe, |
efc6f628 | 643 | struct blkid_magic *id __BLKID_ATTR((unused)), |
038d2bed | 644 | unsigned char *buf) |
c4c740ff | 645 | { |
78d89cda | 646 | struct msdos_super_block *ms; |
c4c740ff | 647 | |
78d89cda | 648 | ms = (struct msdos_super_block *)buf; |
c4c740ff | 649 | |
c4c740ff | 650 | /* heads check */ |
78d89cda | 651 | if (ms->ms_heads == 0) |
c4c740ff KZ |
652 | return 1; |
653 | ||
efc6f628 | 654 | /* cluster size check*/ |
78d89cda TT |
655 | if (ms->ms_cluster_size == 0 || |
656 | (ms->ms_cluster_size & (ms->ms_cluster_size-1))) | |
c4c740ff KZ |
657 | return 1; |
658 | ||
659 | /* media check */ | |
78d89cda | 660 | if (ms->ms_media < 0xf8 && ms->ms_media != 0xf0) |
c4c740ff KZ |
661 | return 1; |
662 | ||
663 | /* fat counts(Linux kernel expects at least 1 FAT table) */ | |
78d89cda TT |
664 | if (!ms->ms_fats) |
665 | return 1; | |
666 | ||
667 | /* | |
668 | * OS/2 and apparently DFSee will place a FAT12/16-like | |
669 | * pseudo-superblock in the first 512 bytes of non-FAT | |
670 | * filesystems --- at least JFS and HPFS, and possibly others. | |
671 | * So we explicitly check for those filesystems at the | |
672 | * FAT12/16 filesystem magic field identifier, and if they are | |
673 | * present, we rule this out as a FAT filesystem, despite the | |
674 | * FAT-like pseudo-header. | |
675 | */ | |
676 | if ((memcmp(ms->ms_magic, "JFS ", 8) == 0) || | |
677 | (memcmp(ms->ms_magic, "HPFS ", 8) == 0)) | |
c4c740ff KZ |
678 | return 1; |
679 | ||
ca749859 | 680 | return probe_fat(probe, id, buf); |
c4c740ff KZ |
681 | } |
682 | ||
cb0c5d70 | 683 | static int probe_ntfs(struct blkid_probe *probe, |
efc6f628 | 684 | struct blkid_magic *id __BLKID_ATTR((unused)), |
cb0c5d70 TT |
685 | unsigned char *buf) |
686 | { | |
687 | struct ntfs_super_block *ns; | |
688 | struct master_file_table_record *mft; | |
689 | struct file_attribute *attr; | |
690 | char uuid_str[17], label_str[129], *cp; | |
691 | int bytes_per_sector, sectors_per_cluster; | |
692 | int mft_record_size, attr_off, attr_len; | |
693 | unsigned int i, attr_type, val_len; | |
694 | int val_off; | |
695 | __u64 nr_clusters; | |
696 | blkid_loff_t off; | |
697 | unsigned char *buf_mft, *val; | |
698 | ||
699 | ns = (struct ntfs_super_block *) buf; | |
700 | ||
701 | bytes_per_sector = ns->bios_parameter_block[0] + | |
702 | (ns->bios_parameter_block[1] << 8); | |
703 | sectors_per_cluster = ns->bios_parameter_block[2]; | |
704 | ||
30dd2622 TT |
705 | if ((bytes_per_sector < 512) || (sectors_per_cluster == 0)) |
706 | return 1; | |
707 | ||
cb0c5d70 | 708 | if (ns->cluster_per_mft_record < 0) |
30dd2622 | 709 | mft_record_size = 1 << (0-ns->cluster_per_mft_record); |
cb0c5d70 | 710 | else |
efc6f628 | 711 | mft_record_size = ns->cluster_per_mft_record * |
cb0c5d70 TT |
712 | sectors_per_cluster * bytes_per_sector; |
713 | nr_clusters = blkid_le64(ns->number_of_sectors) / sectors_per_cluster; | |
714 | ||
715 | if ((blkid_le64(ns->mft_cluster_location) > nr_clusters) || | |
716 | (blkid_le64(ns->mft_mirror_cluster_location) > nr_clusters)) | |
717 | return 1; | |
718 | ||
efc6f628 | 719 | off = blkid_le64(ns->mft_mirror_cluster_location) * |
cb0c5d70 TT |
720 | bytes_per_sector * sectors_per_cluster; |
721 | ||
722 | buf_mft = get_buffer(probe, off, mft_record_size); | |
723 | if (!buf_mft) | |
724 | return 1; | |
725 | ||
726 | if (memcmp(buf_mft, "FILE", 4)) | |
727 | return 1; | |
728 | ||
efc6f628 | 729 | off = blkid_le64(ns->mft_cluster_location) * bytes_per_sector * |
cb0c5d70 TT |
730 | sectors_per_cluster; |
731 | ||
732 | buf_mft = get_buffer(probe, off, mft_record_size); | |
733 | if (!buf_mft) | |
734 | return 1; | |
735 | ||
736 | if (memcmp(buf_mft, "FILE", 4)) | |
737 | return 1; | |
738 | ||
739 | off += MFT_RECORD_VOLUME * mft_record_size; | |
740 | ||
741 | buf_mft = get_buffer(probe, off, mft_record_size); | |
742 | if (!buf_mft) | |
743 | return 1; | |
744 | ||
745 | if (memcmp(buf_mft, "FILE", 4)) | |
746 | return 1; | |
747 | ||
748 | mft = (struct master_file_table_record *) buf_mft; | |
749 | ||
750 | attr_off = blkid_le16(mft->attrs_offset); | |
751 | label_str[0] = 0; | |
efc6f628 | 752 | |
cb0c5d70 TT |
753 | while (1) { |
754 | attr = (struct file_attribute *) (buf_mft + attr_off); | |
755 | attr_len = blkid_le16(attr->len); | |
756 | attr_type = blkid_le32(attr->type); | |
757 | val_off = blkid_le16(attr->value_offset); | |
758 | val_len = blkid_le32(attr->value_len); | |
759 | ||
760 | attr_off += attr_len; | |
761 | ||
762 | if ((attr_off > mft_record_size) || | |
763 | (attr_len == 0)) | |
764 | break; | |
765 | ||
766 | if (attr_type == MFT_RECORD_ATTR_END) | |
767 | break; | |
768 | ||
769 | if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) { | |
770 | if (val_len > sizeof(label_str)) | |
771 | val_len = sizeof(label_str)-1; | |
772 | ||
773 | for (i=0, cp=label_str; i < val_len; i+=2,cp++) { | |
774 | val = ((__u8 *) attr) + val_off + i; | |
775 | *cp = val[0]; | |
776 | if (val[1]) | |
777 | *cp = '?'; | |
778 | } | |
779 | *cp = 0; | |
780 | } | |
781 | } | |
782 | ||
c40ad367 | 783 | sprintf(uuid_str, "%016llX", blkid_le64(ns->volume_serial)); |
cb0c5d70 TT |
784 | blkid_set_tag(probe->dev, "UUID", uuid_str, 0); |
785 | if (label_str[0]) | |
786 | blkid_set_tag(probe->dev, "LABEL", label_str, 0); | |
787 | return 0; | |
788 | } | |
789 | ||
790 | ||
ca749859 | 791 | static int probe_xfs(struct blkid_probe *probe, |
efc6f628 | 792 | struct blkid_magic *id __BLKID_ATTR((unused)), |
54434927 | 793 | unsigned char *buf) |
e12f2ae7 | 794 | { |
e12f2ae7 | 795 | struct xfs_super_block *xs; |
a30b9446 | 796 | const char *label = 0; |
e12f2ae7 TT |
797 | |
798 | xs = (struct xfs_super_block *)buf; | |
799 | ||
e12f2ae7 | 800 | if (strlen(xs->xs_fname)) |
a30b9446 | 801 | label = xs->xs_fname; |
ca749859 | 802 | blkid_set_tag(probe->dev, "LABEL", label, sizeof(xs->xs_fname)); |
ba5e3849 | 803 | set_uuid(probe->dev, xs->xs_uuid, 0); |
e12f2ae7 TT |
804 | return 0; |
805 | } | |
806 | ||
ca749859 | 807 | static int probe_reiserfs(struct blkid_probe *probe, |
79dd234a | 808 | struct blkid_magic *id, unsigned char *buf) |
e12f2ae7 | 809 | { |
50b380b4 | 810 | struct reiserfs_super_block *rs = (struct reiserfs_super_block *) buf; |
e12f2ae7 | 811 | unsigned int blocksize; |
a30b9446 | 812 | const char *label = 0; |
e12f2ae7 | 813 | |
76b07bb1 | 814 | blocksize = blkid_le16(rs->rs_blocksize); |
e12f2ae7 | 815 | |
4dc30dac TT |
816 | /* The blocksize must be at least 1k */ |
817 | if ((blocksize >> 10) == 0) | |
818 | return -BLKID_ERR_PARAM; | |
819 | ||
e12f2ae7 | 820 | /* If the superblock is inside the journal, we have the wrong one */ |
50b380b4 | 821 | if (id->bim_kboff/(blocksize>>10) > blkid_le32(rs->rs_journal_block)) |
e12f2ae7 | 822 | return -BLKID_ERR_BIG; |
e12f2ae7 TT |
823 | |
824 | /* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */ | |
ca749859 | 825 | if (id->bim_magic[6] == '2' || id->bim_magic[6] == '3') { |
a30b9446 TT |
826 | if (strlen(rs->rs_label)) |
827 | label = rs->rs_label; | |
ba5e3849 | 828 | set_uuid(probe->dev, rs->rs_uuid, 0); |
e12f2ae7 | 829 | } |
ca749859 | 830 | blkid_set_tag(probe->dev, "LABEL", label, sizeof(rs->rs_label)); |
e12f2ae7 TT |
831 | |
832 | return 0; | |
833 | } | |
834 | ||
ca749859 | 835 | static int probe_reiserfs4(struct blkid_probe *probe, |
efc6f628 | 836 | struct blkid_magic *id __BLKID_ATTR((unused)), |
ca749859 | 837 | unsigned char *buf) |
bb626bcd TT |
838 | { |
839 | struct reiser4_super_block *rs4 = (struct reiser4_super_block *) buf; | |
ca749859 | 840 | const unsigned char *label = 0; |
bb626bcd | 841 | |
ca749859 | 842 | if (strlen((char *) rs4->rs4_label)) |
bb626bcd | 843 | label = rs4->rs4_label; |
ba5e3849 | 844 | set_uuid(probe->dev, rs4->rs4_uuid, 0); |
efc6f628 | 845 | blkid_set_tag(probe->dev, "LABEL", (const char *) label, |
ca749859 | 846 | sizeof(rs4->rs4_label)); |
bb626bcd TT |
847 | |
848 | return 0; | |
849 | } | |
850 | ||
ca749859 | 851 | static int probe_jfs(struct blkid_probe *probe, |
efc6f628 | 852 | struct blkid_magic *id __BLKID_ATTR((unused)), |
54434927 | 853 | unsigned char *buf) |
09a2ef8d TT |
854 | { |
855 | struct jfs_super_block *js; | |
a30b9446 | 856 | const char *label = 0; |
09a2ef8d TT |
857 | |
858 | js = (struct jfs_super_block *)buf; | |
859 | ||
b41fb002 TT |
860 | if (blkid_le32(js->js_bsize) != (1 << blkid_le16(js->js_l2bsize))) |
861 | return 1; | |
862 | ||
863 | if (blkid_le32(js->js_pbsize) != (1 << blkid_le16(js->js_l2pbsize))) | |
864 | return 1; | |
865 | ||
866 | if ((blkid_le16(js->js_l2bsize) - blkid_le16(js->js_l2pbsize)) != | |
867 | blkid_le16(js->js_l2bfactor)) | |
868 | return 1; | |
869 | ||
48e6e813 | 870 | if (strlen((char *) js->js_label)) |
a30b9446 | 871 | label = (char *) js->js_label; |
ca749859 | 872 | blkid_set_tag(probe->dev, "LABEL", label, sizeof(js->js_label)); |
ba5e3849 | 873 | set_uuid(probe->dev, js->js_uuid, 0); |
09a2ef8d TT |
874 | return 0; |
875 | } | |
876 | ||
25f291c9 TT |
877 | static int probe_zfs(struct blkid_probe *probe __BLKID_ATTR((unused)), |
878 | struct blkid_magic *id __BLKID_ATTR((unused)), | |
879 | unsigned char *buf __BLKID_ATTR((unused))) | |
c9bad3ce | 880 | { |
79e62409 | 881 | #if 0 |
c9bad3ce RC |
882 | char *vdev_label; |
883 | const char *pool_name = 0; | |
884 | ||
885 | /* read nvpair data for pool name, pool GUID (complex) */ | |
c9bad3ce RC |
886 | blkid_set_tag(probe->dev, "LABEL", pool_name, sizeof(pool_name)); |
887 | set_uuid(probe->dev, pool_guid, 0); | |
888 | #endif | |
889 | return 0; | |
890 | } | |
891 | ||
e382a7ea KH |
892 | static int probe_luks(struct blkid_probe *probe, |
893 | struct blkid_magic *id __BLKID_ATTR((unused)), | |
894 | unsigned char *buf) | |
895 | { | |
d4e0b1c6 TT |
896 | char uuid[40]; |
897 | ||
e382a7ea KH |
898 | /* 168 is the offset to the 40 character uuid: |
899 | * http://luks.endorphin.org/LUKS-on-disk-format.pdf */ | |
d4e0b1c6 | 900 | strncpy(uuid, (char *) buf+168, 40); |
e382a7ea KH |
901 | blkid_set_tag(probe->dev, "UUID", uuid, sizeof(uuid)); |
902 | return 0; | |
903 | } | |
904 | ||
ca749859 | 905 | static int probe_romfs(struct blkid_probe *probe, |
efc6f628 | 906 | struct blkid_magic *id __BLKID_ATTR((unused)), |
54434927 | 907 | unsigned char *buf) |
09a2ef8d TT |
908 | { |
909 | struct romfs_super_block *ros; | |
a30b9446 | 910 | const char *label = 0; |
09a2ef8d TT |
911 | |
912 | ros = (struct romfs_super_block *)buf; | |
913 | ||
a30b9446 TT |
914 | if (strlen((char *) ros->ros_volume)) |
915 | label = (char *) ros->ros_volume; | |
ca749859 | 916 | blkid_set_tag(probe->dev, "LABEL", label, 0); |
7369f0ce TT |
917 | return 0; |
918 | } | |
919 | ||
ca749859 | 920 | static int probe_cramfs(struct blkid_probe *probe, |
efc6f628 | 921 | struct blkid_magic *id __BLKID_ATTR((unused)), |
ca749859 | 922 | unsigned char *buf) |
4c4e3f78 TT |
923 | { |
924 | struct cramfs_super_block *csb; | |
925 | const char *label = 0; | |
926 | ||
927 | csb = (struct cramfs_super_block *)buf; | |
928 | ||
929 | if (strlen((char *) csb->name)) | |
930 | label = (char *) csb->name; | |
ca749859 | 931 | blkid_set_tag(probe->dev, "LABEL", label, 0); |
4c4e3f78 TT |
932 | return 0; |
933 | } | |
934 | ||
ca749859 | 935 | static int probe_swap0(struct blkid_probe *probe, |
7369f0ce TT |
936 | struct blkid_magic *id __BLKID_ATTR((unused)), |
937 | unsigned char *buf __BLKID_ATTR((unused))) | |
938 | { | |
ca749859 TT |
939 | blkid_set_tag(probe->dev, "UUID", 0, 0); |
940 | blkid_set_tag(probe->dev, "LABEL", 0, 0); | |
7369f0ce TT |
941 | return 0; |
942 | } | |
943 | ||
ca749859 | 944 | static int probe_swap1(struct blkid_probe *probe, |
6360d129 | 945 | struct blkid_magic *id, |
7369f0ce TT |
946 | unsigned char *buf __BLKID_ATTR((unused))) |
947 | { | |
948 | struct swap_id_block *sws; | |
7369f0ce | 949 | |
ca749859 | 950 | probe_swap0(probe, id, buf); |
7369f0ce TT |
951 | /* |
952 | * Version 1 swap headers are always located at offset of 1024 | |
953 | * bytes, although the swap signature itself is located at the | |
954 | * end of the page (which may vary depending on hardware | |
955 | * pagesize). | |
956 | */ | |
ca749859 TT |
957 | sws = (struct swap_id_block *) get_buffer(probe, 1024, 1024); |
958 | if (!sws) | |
7369f0ce | 959 | return 1; |
7369f0ce | 960 | |
6360d129 ES |
961 | /* check for wrong version or zeroed pagecount, for sanity */ |
962 | if (!memcmp(id->bim_magic, "SWAPSPACE2", id->bim_len) && | |
22269b8b | 963 | (sws->sws_version != 1 || sws->sws_lastpage == 0)) |
6360d129 ES |
964 | return 1; |
965 | ||
7369f0ce TT |
966 | /* arbitrary sanity check.. is there any garbage down there? */ |
967 | if (sws->sws_pad[32] == 0 && sws->sws_pad[33] == 0) { | |
968 | if (sws->sws_volume[0]) | |
efc6f628 | 969 | blkid_set_tag(probe->dev, "LABEL", sws->sws_volume, |
7369f0ce TT |
970 | sizeof(sws->sws_volume)); |
971 | if (sws->sws_uuid[0]) | |
ba5e3849 | 972 | set_uuid(probe->dev, sws->sws_uuid, 0); |
7369f0ce | 973 | } |
09a2ef8d TT |
974 | return 0; |
975 | } | |
976 | ||
ca749859 | 977 | static int probe_iso9660(struct blkid_probe *probe, |
efc6f628 | 978 | struct blkid_magic *id __BLKID_ATTR((unused)), |
45a3fa87 TT |
979 | unsigned char *buf) |
980 | { | |
981 | struct iso_volume_descriptor *iso; | |
982 | const unsigned char *label; | |
983 | ||
984 | iso = (struct iso_volume_descriptor *) buf; | |
45a3fa87 TT |
985 | label = iso->volume_id; |
986 | ||
efc6f628 | 987 | blkid_set_tag(probe->dev, "LABEL", (const char *) label, |
ca749859 | 988 | figure_label_len(label, 32)); |
45a3fa87 TT |
989 | return 0; |
990 | } | |
991 | ||
992 | ||
54434927 | 993 | static const char |
3de5bf61 TT |
994 | *udf_magic[] = { "BEA01", "BOOT2", "CD001", "CDW02", "NSR02", |
995 | "NSR03", "TEA01", 0 }; | |
996 | ||
ca749859 | 997 | static int probe_udf(struct blkid_probe *probe, |
efc6f628 | 998 | struct blkid_magic *id __BLKID_ATTR((unused)), |
54434927 | 999 | unsigned char *buf __BLKID_ATTR((unused))) |
3de5bf61 TT |
1000 | { |
1001 | int j, bs; | |
ca749859 | 1002 | struct iso_volume_descriptor *isosb; |
54434927 | 1003 | const char ** m; |
3de5bf61 TT |
1004 | |
1005 | /* determine the block size by scanning in 2K increments | |
1006 | (block sizes larger than 2K will be null padded) */ | |
1007 | for (bs = 1; bs < 16; bs++) { | |
efc6f628 | 1008 | isosb = (struct iso_volume_descriptor *) |
d1da14b5 TT |
1009 | get_buffer(probe, (blkid_loff_t) bs*2048+32768, |
1010 | sizeof(*isosb)); | |
ca749859 | 1011 | if (!isosb) |
3de5bf61 | 1012 | return 1; |
ca749859 | 1013 | if (isosb->vd_id[0]) |
3de5bf61 TT |
1014 | break; |
1015 | } | |
1016 | ||
1017 | /* Scan up to another 64 blocks looking for additional VSD's */ | |
1018 | for (j = 1; j < 64; j++) { | |
1019 | if (j > 1) { | |
efc6f628 TT |
1020 | isosb = (struct iso_volume_descriptor *) |
1021 | get_buffer(probe, j*bs*2048+32768, | |
75954ccf | 1022 | sizeof(*isosb)); |
ca749859 | 1023 | if (!isosb) |
3de5bf61 TT |
1024 | return 1; |
1025 | } | |
1026 | /* If we find NSR0x then call it udf: | |
1027 | NSR01 for UDF 1.00 | |
1028 | NSR02 for UDF 1.50 | |
1029 | NSR03 for UDF 2.00 */ | |
49487b79 | 1030 | if (!memcmp(isosb->vd_id, "NSR0", 4)) |
a4045c21 | 1031 | return probe_iso9660(probe, id, buf); |
3de5bf61 | 1032 | for (m = udf_magic; *m; m++) |
49487b79 | 1033 | if (!memcmp(*m, isosb->vd_id, 5)) |
3de5bf61 TT |
1034 | break; |
1035 | if (*m == 0) | |
1036 | return 1; | |
1037 | } | |
1038 | return 1; | |
1039 | } | |
1040 | ||
ca749859 | 1041 | static int probe_ocfs(struct blkid_probe *probe, |
efc6f628 | 1042 | struct blkid_magic *id __BLKID_ATTR((unused)), |
9387c281 TT |
1043 | unsigned char *buf) |
1044 | { | |
1045 | struct ocfs_volume_header ovh; | |
1046 | struct ocfs_volume_label ovl; | |
3838f7df | 1047 | __u32 major; |
9387c281 TT |
1048 | |
1049 | memcpy(&ovh, buf, sizeof(ovh)); | |
1050 | memcpy(&ovl, buf+512, sizeof(ovl)); | |
1051 | ||
1052 | major = ocfsmajor(ovh); | |
1053 | if (major == 1) | |
ca749859 | 1054 | blkid_set_tag(probe->dev,"SEC_TYPE","ocfs1",sizeof("ocfs1")); |
9387c281 | 1055 | else if (major >= 9) |
ca749859 | 1056 | blkid_set_tag(probe->dev,"SEC_TYPE","ntocfs",sizeof("ntocfs")); |
efc6f628 | 1057 | |
ca749859 TT |
1058 | blkid_set_tag(probe->dev, "LABEL", ovl.label, ocfslabellen(ovl)); |
1059 | blkid_set_tag(probe->dev, "MOUNT", ovh.mount, ocfsmountlen(ovh)); | |
ba5e3849 | 1060 | set_uuid(probe->dev, ovl.vol_id, 0); |
9387c281 TT |
1061 | return 0; |
1062 | } | |
1063 | ||
ca749859 | 1064 | static int probe_ocfs2(struct blkid_probe *probe, |
efc6f628 | 1065 | struct blkid_magic *id __BLKID_ATTR((unused)), |
2c92375e | 1066 | unsigned char *buf) |
414846b1 TT |
1067 | { |
1068 | struct ocfs2_super_block *osb; | |
1069 | ||
1070 | osb = (struct ocfs2_super_block *)buf; | |
1071 | ||
ca749859 | 1072 | blkid_set_tag(probe->dev, "LABEL", osb->s_label, sizeof(osb->s_label)); |
ba5e3849 | 1073 | set_uuid(probe->dev, osb->s_uuid, 0); |
414846b1 TT |
1074 | return 0; |
1075 | } | |
1076 | ||
ca749859 | 1077 | static int probe_oracleasm(struct blkid_probe *probe, |
efc6f628 | 1078 | struct blkid_magic *id __BLKID_ATTR((unused)), |
2c92375e TT |
1079 | unsigned char *buf) |
1080 | { | |
1081 | struct oracle_asm_disk_label *dl; | |
1082 | ||
1083 | dl = (struct oracle_asm_disk_label *)buf; | |
1084 | ||
ca749859 | 1085 | blkid_set_tag(probe->dev, "LABEL", dl->dl_id, sizeof(dl->dl_id)); |
2c92375e TT |
1086 | return 0; |
1087 | } | |
1088 | ||
b5517ca6 KZ |
1089 | static int probe_gfs(struct blkid_probe *probe, |
1090 | struct blkid_magic *id __BLKID_ATTR((unused)), | |
1091 | unsigned char *buf) | |
1092 | { | |
1093 | struct gfs2_sb *sbd; | |
1094 | const char *label = 0; | |
1095 | ||
1096 | sbd = (struct gfs2_sb *)buf; | |
1097 | ||
1098 | if (blkid_be32(sbd->sb_fs_format) == GFS_FORMAT_FS && | |
1099 | blkid_be32(sbd->sb_multihost_format) == GFS_FORMAT_MULTI) | |
efc6f628 | 1100 | { |
b5517ca6 | 1101 | blkid_set_tag(probe->dev, "UUID", 0, 0); |
efc6f628 | 1102 | |
b5517ca6 KZ |
1103 | if (strlen(sbd->sb_locktable)) |
1104 | label = sbd->sb_locktable; | |
1105 | blkid_set_tag(probe->dev, "LABEL", label, sizeof(sbd->sb_locktable)); | |
1106 | return 0; | |
1107 | } | |
1108 | return 1; | |
1109 | } | |
1110 | ||
1111 | static int probe_gfs2(struct blkid_probe *probe, | |
1112 | struct blkid_magic *id __BLKID_ATTR((unused)), | |
1113 | unsigned char *buf) | |
1114 | { | |
1115 | struct gfs2_sb *sbd; | |
1116 | const char *label = 0; | |
1117 | ||
1118 | sbd = (struct gfs2_sb *)buf; | |
1119 | ||
1120 | if (blkid_be32(sbd->sb_fs_format) == GFS2_FORMAT_FS && | |
1121 | blkid_be32(sbd->sb_multihost_format) == GFS2_FORMAT_MULTI) | |
efc6f628 | 1122 | { |
b5517ca6 | 1123 | blkid_set_tag(probe->dev, "UUID", 0, 0); |
efc6f628 | 1124 | |
b5517ca6 KZ |
1125 | if (strlen(sbd->sb_locktable)) |
1126 | label = sbd->sb_locktable; | |
1127 | blkid_set_tag(probe->dev, "LABEL", label, sizeof(sbd->sb_locktable)); | |
1128 | return 0; | |
1129 | } | |
1130 | return 1; | |
1131 | } | |
1132 | ||
efc6f628 | 1133 | static void unicode_16be_to_utf8(unsigned char *str, int out_len, |
d56ccbd8 | 1134 | const unsigned char *buf, int in_len) |
9c460caa TT |
1135 | { |
1136 | int i, j; | |
1137 | unsigned int c; | |
1138 | ||
1139 | for (i = j = 0; i + 2 <= in_len; i += 2) { | |
1140 | c = (buf[i] << 8) | buf[i+1]; | |
1141 | if (c == 0) { | |
1142 | str[j] = '\0'; | |
1143 | break; | |
1144 | } else if (c < 0x80) { | |
1145 | if (j+1 >= out_len) | |
1146 | break; | |
1147 | str[j++] = (unsigned char) c; | |
1148 | } else if (c < 0x800) { | |
1149 | if (j+2 >= out_len) | |
1150 | break; | |
1151 | str[j++] = (unsigned char) (0xc0 | (c >> 6)); | |
1152 | str[j++] = (unsigned char) (0x80 | (c & 0x3f)); | |
1153 | } else { | |
1154 | if (j+3 >= out_len) | |
1155 | break; | |
1156 | str[j++] = (unsigned char) (0xe0 | (c >> 12)); | |
1157 | str[j++] = (unsigned char) (0x80 | ((c >> 6) & 0x3f)); | |
1158 | str[j++] = (unsigned char) (0x80 | (c & 0x3f)); | |
1159 | } | |
1160 | } | |
1161 | str[j] = '\0'; | |
1162 | } | |
1163 | ||
1164 | static int probe_hfs(struct blkid_probe *probe __BLKID_ATTR((unused)), | |
69d74228 TT |
1165 | struct blkid_magic *id __BLKID_ATTR((unused)), |
1166 | unsigned char *buf) | |
1167 | { | |
00eb0eee AD |
1168 | struct hfs_mdb *hfs = (struct hfs_mdb *)buf; |
1169 | unsigned long long *uuid_ptr; | |
9c460caa TT |
1170 | char uuid_str[17]; |
1171 | __u64 uuid; | |
1172 | ||
1173 | if ((memcmp(hfs->embed_sig, "H+", 2) == 0) || | |
1174 | (memcmp(hfs->embed_sig, "HX", 2) == 0)) | |
1175 | return 1; /* Not hfs, but an embedded HFS+ */ | |
1176 | ||
00eb0eee AD |
1177 | uuid_ptr = (unsigned long long *)hfs->finder_info.id; |
1178 | uuid = blkid_le64(*uuid_ptr); | |
9c460caa TT |
1179 | if (uuid) { |
1180 | sprintf(uuid_str, "%016llX", uuid); | |
1181 | blkid_set_tag(probe->dev, "UUID", uuid_str, 0); | |
1182 | } | |
cf5301d7 | 1183 | blkid_set_tag(probe->dev, "LABEL", (char *)hfs->label, hfs->label_len); |
9c460caa TT |
1184 | return 0; |
1185 | } | |
1186 | ||
1187 | ||
1188 | static int probe_hfsplus(struct blkid_probe *probe, | |
1189 | struct blkid_magic *id, | |
1190 | unsigned char *buf) | |
1191 | { | |
1192 | struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT]; | |
1193 | struct hfsplus_bnode_descriptor *descr; | |
1194 | struct hfsplus_bheader_record *bnode; | |
1195 | struct hfsplus_catalog_key *key; | |
1196 | struct hfsplus_vol_header *hfsplus; | |
1197 | struct hfs_mdb *sbd = (struct hfs_mdb *) buf; | |
1198 | unsigned int alloc_block_size; | |
1199 | unsigned int alloc_first_block; | |
1200 | unsigned int embed_first_block; | |
1201 | unsigned int off = 0; | |
1202 | unsigned int blocksize; | |
1203 | unsigned int cat_block; | |
1204 | unsigned int ext_block_start; | |
1205 | unsigned int ext_block_count; | |
1206 | unsigned int record_count; | |
1207 | unsigned int leaf_node_head; | |
1208 | unsigned int leaf_node_count; | |
1209 | unsigned int leaf_node_size; | |
1210 | unsigned int leaf_block; | |
1211 | unsigned int label_len; | |
00eb0eee | 1212 | unsigned long long *uuid_ptr; |
9c460caa TT |
1213 | __u64 leaf_off, uuid; |
1214 | char uuid_str[17], label[512]; | |
00eb0eee | 1215 | int ext; |
69d74228 TT |
1216 | |
1217 | /* Check for a HFS+ volume embedded in a HFS volume */ | |
9c460caa TT |
1218 | if (memcmp(sbd->signature, "BD", 2) == 0) { |
1219 | if ((memcmp(sbd->embed_sig, "H+", 2) != 0) && | |
1220 | (memcmp(sbd->embed_sig, "HX", 2) != 0)) | |
1221 | /* This must be an HFS volume, so fail */ | |
1222 | return 1; | |
efc6f628 | 1223 | |
9c460caa TT |
1224 | alloc_block_size = blkid_be32(sbd->al_blk_size); |
1225 | alloc_first_block = blkid_be16(sbd->al_bl_st); | |
1226 | embed_first_block = blkid_be16(sbd->embed_startblock); | |
1227 | off = (alloc_first_block * 512) + | |
1228 | (embed_first_block * alloc_block_size); | |
1229 | buf = get_buffer(probe, off + (id->bim_kboff * 1024), | |
75954ccf | 1230 | sizeof(*sbd)); |
9c460caa TT |
1231 | if (!buf) |
1232 | return 1; | |
1233 | ||
1234 | hfsplus = (struct hfsplus_vol_header *) buf; | |
1235 | } | |
1236 | ||
1237 | hfsplus = (struct hfsplus_vol_header *) buf; | |
1238 | ||
1239 | if ((memcmp(hfsplus->signature, "H+", 2) != 0) && | |
1240 | (memcmp(hfsplus->signature, "HX", 2) != 0)) | |
1241 | return 1; | |
1242 | ||
00eb0eee AD |
1243 | uuid_ptr = (unsigned long long *)hfsplus->finder_info.id; |
1244 | uuid = blkid_le64(*uuid_ptr); | |
9c460caa TT |
1245 | if (uuid) { |
1246 | sprintf(uuid_str, "%016llX", uuid); | |
1247 | blkid_set_tag(probe->dev, "UUID", uuid_str, 0); | |
1248 | } | |
1249 | ||
1250 | blocksize = blkid_be32(hfsplus->blocksize); | |
1251 | memcpy(extents, hfsplus->cat_file.extents, sizeof(extents)); | |
1252 | cat_block = blkid_be32(extents[0].start_block); | |
1253 | ||
d1da14b5 | 1254 | buf = get_buffer(probe, off + ((__u64) cat_block * blocksize), 0x2000); |
9c460caa | 1255 | if (!buf) |
69d74228 TT |
1256 | return 0; |
1257 | ||
9c460caa TT |
1258 | bnode = (struct hfsplus_bheader_record *) |
1259 | &buf[sizeof(struct hfsplus_bnode_descriptor)]; | |
1260 | ||
1261 | leaf_node_head = blkid_be32(bnode->leaf_head); | |
1262 | leaf_node_size = blkid_be16(bnode->node_size); | |
1263 | leaf_node_count = blkid_be32(bnode->leaf_count); | |
1264 | if (leaf_node_count == 0) | |
1265 | return 0; | |
1266 | ||
1267 | leaf_block = (leaf_node_head * leaf_node_size) / blocksize; | |
1268 | ||
1269 | /* get physical location */ | |
1270 | for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) { | |
1271 | ext_block_start = blkid_be32(extents[ext].start_block); | |
1272 | ext_block_count = blkid_be32(extents[ext].block_count); | |
1273 | if (ext_block_count == 0) | |
1274 | return 0; | |
1275 | ||
1276 | /* this is our extent */ | |
1277 | if (leaf_block < ext_block_count) | |
1278 | break; | |
1279 | ||
1280 | leaf_block -= ext_block_count; | |
1281 | } | |
1282 | if (ext == HFSPLUS_EXTENT_COUNT) | |
1283 | return 0; | |
1284 | ||
d1da14b5 | 1285 | leaf_off = (__u64) (ext_block_start + leaf_block) * blocksize; |
9c460caa TT |
1286 | |
1287 | buf = get_buffer(probe, off + leaf_off, leaf_node_size); | |
1288 | if (!buf) | |
1289 | return 0; | |
1290 | ||
1291 | descr = (struct hfsplus_bnode_descriptor *) buf; | |
1292 | record_count = blkid_be16(descr->num_recs); | |
1293 | if (record_count == 0) | |
1294 | return 0; | |
1295 | ||
1296 | if (descr->type != HFS_NODE_LEAF) | |
1297 | return 0; | |
1298 | ||
1299 | key = (struct hfsplus_catalog_key *) | |
1300 | &buf[sizeof(struct hfsplus_bnode_descriptor)]; | |
1301 | ||
1302 | if (blkid_be32(key->parent_id) != HFSPLUS_POR_CNID) | |
1303 | return 0; | |
1304 | ||
1305 | label_len = blkid_be16(key->unicode_len) * 2; | |
cf5301d7 AD |
1306 | unicode_16be_to_utf8((unsigned char *)label, sizeof(label), |
1307 | key->unicode, label_len); | |
9c460caa TT |
1308 | blkid_set_tag(probe->dev, "LABEL", label, 0); |
1309 | return 0; | |
69d74228 TT |
1310 | } |
1311 | ||
a451d92f | 1312 | #define LVM2_LABEL_SIZE 512 |
dd232049 | 1313 | static unsigned int lvm2_calc_crc(const void *buf, unsigned int size) |
a451d92f | 1314 | { |
dd232049 | 1315 | static const unsigned int crctab[] = { |
a451d92f ES |
1316 | 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, |
1317 | 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, | |
1318 | 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, | |
1319 | 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c | |
1320 | }; | |
dd232049 | 1321 | unsigned int i, crc = 0xf597a6cf; |
a451d92f ES |
1322 | const __u8 *data = (const __u8 *) buf; |
1323 | ||
1324 | for (i = 0; i < size; i++) { | |
1325 | crc ^= *data++; | |
1326 | crc = (crc >> 4) ^ crctab[crc & 0xf]; | |
1327 | crc = (crc >> 4) ^ crctab[crc & 0xf]; | |
1328 | } | |
1329 | return crc; | |
1330 | } | |
1331 | ||
1332 | static int probe_lvm2(struct blkid_probe *probe, | |
cc19b958 | 1333 | struct blkid_magic *id, |
a451d92f ES |
1334 | unsigned char *buf) |
1335 | { | |
8d45e210 | 1336 | int sector = (id->bim_kboff) << 1; |
cc19b958 | 1337 | struct lvm2_pv_label_header *label= (struct lvm2_pv_label_header *)buf; |
a451d92f ES |
1338 | char *p, *q, uuid[40]; |
1339 | unsigned int i, b; | |
1340 | ||
1341 | /* buf is at 0k or 1k offset; find label inside */ | |
1342 | if (memcmp(buf, "LABELONE", 8) == 0) { | |
1343 | label = (struct lvm2_pv_label_header *)buf; | |
1344 | } else if (memcmp(buf + 512, "LABELONE", 8) == 0) { | |
1345 | label = (struct lvm2_pv_label_header *)(buf + 512); | |
1346 | sector++; | |
1347 | } else { | |
1348 | return 1; | |
1349 | } | |
1350 | ||
3a538e42 | 1351 | if (blkid_le64(label->sector_xl) != (unsigned) sector) { |
a451d92f | 1352 | DBG(DEBUG_PROBE, |
3a538e42 | 1353 | printf("LVM2: label for sector %llu found at sector %d\n", |
a451d92f ES |
1354 | blkid_le64(label->sector_xl), sector)); |
1355 | return 1; | |
1356 | } | |
1357 | ||
1358 | if (lvm2_calc_crc(&label->offset_xl, LVM2_LABEL_SIZE - | |
3a538e42 | 1359 | ((char *)&label->offset_xl - (char *)label)) != |
a451d92f ES |
1360 | blkid_le32(label->crc_xl)) { |
1361 | DBG(DEBUG_PROBE, | |
1362 | printf("LVM2: label checksum incorrect at sector %d\n", | |
1363 | sector)); | |
1364 | return 1; | |
1365 | } | |
1366 | ||
5d5576d8 | 1367 | for (i=0, b=1, p=uuid, q= (char *) label->pv_uuid; i < LVM2_ID_LEN; |
3a538e42 | 1368 | i++, b <<= 1) { |
a451d92f ES |
1369 | if (b & 0x4444440) |
1370 | *p++ = '-'; | |
1371 | *p++ = *q++; | |
1372 | } | |
1373 | ||
1374 | blkid_set_tag(probe->dev, "UUID", uuid, LVM2_ID_LEN+6); | |
1375 | ||
1376 | return 0; | |
1377 | } | |
801b0053 ES |
1378 | |
1379 | static int probe_btrfs(struct blkid_probe *probe, | |
25f291c9 | 1380 | struct blkid_magic *id __BLKID_ATTR((unused)), |
801b0053 ES |
1381 | unsigned char *buf) |
1382 | { | |
1383 | struct btrfs_super_block *bs; | |
1384 | const char *label = 0; | |
1385 | ||
1386 | bs = (struct btrfs_super_block *)buf; | |
1387 | ||
1388 | if (strlen(bs->label)) | |
1389 | label = bs->label; | |
1390 | blkid_set_tag(probe->dev, "LABEL", label, sizeof(bs->label)); | |
1391 | set_uuid(probe->dev, bs->fsid, 0); | |
1392 | return 0; | |
1393 | } | |
e12f2ae7 TT |
1394 | /* |
1395 | * Various filesystem magics that we can check for. Note that kboff and | |
1396 | * sboff are in kilobytes and bytes respectively. All magics are in | |
1397 | * byte strings so we don't worry about endian issues. | |
1398 | */ | |
50b380b4 TT |
1399 | static struct blkid_magic type_array[] = { |
1400 | /* type kboff sboff len magic probe */ | |
2c92375e | 1401 | { "oracleasm", 0, 32, 8, "ORCLDISK", probe_oracleasm }, |
cb0c5d70 | 1402 | { "ntfs", 0, 3, 8, "NTFS ", probe_ntfs }, |
50b380b4 | 1403 | { "jbd", 1, 0x38, 2, "\123\357", probe_jbd }, |
2921332f TT |
1404 | { "ext4dev", 1, 0x38, 2, "\123\357", probe_ext4dev }, |
1405 | { "ext4", 1, 0x38, 2, "\123\357", probe_ext4 }, | |
2e6a9feb | 1406 | { "ext3", 1, 0x38, 2, "\123\357", probe_ext3 }, |
50b380b4 TT |
1407 | { "ext2", 1, 0x38, 2, "\123\357", probe_ext2 }, |
1408 | { "reiserfs", 8, 0x34, 8, "ReIsErFs", probe_reiserfs }, | |
1409 | { "reiserfs", 64, 0x34, 9, "ReIsEr2Fs", probe_reiserfs }, | |
1410 | { "reiserfs", 64, 0x34, 9, "ReIsEr3Fs", probe_reiserfs }, | |
1411 | { "reiserfs", 64, 0x34, 8, "ReIsErFs", probe_reiserfs }, | |
1412 | { "reiserfs", 8, 20, 8, "ReIsErFs", probe_reiserfs }, | |
bb626bcd | 1413 | { "reiser4", 64, 0, 7, "ReIsEr4", probe_reiserfs4 }, |
b5517ca6 KZ |
1414 | { "gfs2", 64, 0, 4, "\x01\x16\x19\x70", probe_gfs2 }, |
1415 | { "gfs", 64, 0, 4, "\x01\x16\x19\x70", probe_gfs }, | |
038d2bed TT |
1416 | { "vfat", 0, 0x52, 5, "MSWIN", probe_fat }, |
1417 | { "vfat", 0, 0x52, 8, "FAT32 ", probe_fat }, | |
1418 | { "vfat", 0, 0x36, 5, "MSDOS", probe_fat }, | |
1419 | { "vfat", 0, 0x36, 8, "FAT16 ", probe_fat }, | |
1420 | { "vfat", 0, 0x36, 8, "FAT12 ", probe_fat }, | |
846be6db | 1421 | { "vfat", 0, 0, 1, "\353", probe_fat_nomagic }, |
038d2bed | 1422 | { "vfat", 0, 0, 1, "\351", probe_fat_nomagic }, |
846be6db | 1423 | { "vfat", 0, 0x1fe, 2, "\125\252", probe_fat_nomagic }, |
50b380b4 TT |
1424 | { "minix", 1, 0x10, 2, "\177\023", 0 }, |
1425 | { "minix", 1, 0x10, 2, "\217\023", 0 }, | |
1426 | { "minix", 1, 0x10, 2, "\150\044", 0 }, | |
1427 | { "minix", 1, 0x10, 2, "\170\044", 0 }, | |
1428 | { "vxfs", 1, 0, 4, "\365\374\001\245", 0 }, | |
1429 | { "xfs", 0, 0, 4, "XFSB", probe_xfs }, | |
09a2ef8d | 1430 | { "romfs", 0, 0, 8, "-rom1fs-", probe_romfs }, |
50b380b4 | 1431 | { "bfs", 0, 0, 4, "\316\372\173\033", 0 }, |
4c4e3f78 | 1432 | { "cramfs", 0, 0, 4, "E=\315\050", probe_cramfs }, |
50b380b4 | 1433 | { "qnx4", 0, 4, 6, "QNX4FS", 0 }, |
3de5bf61 TT |
1434 | { "udf", 32, 1, 5, "BEA01", probe_udf }, |
1435 | { "udf", 32, 1, 5, "BOOT2", probe_udf }, | |
1436 | { "udf", 32, 1, 5, "CD001", probe_udf }, | |
1437 | { "udf", 32, 1, 5, "CDW02", probe_udf }, | |
1438 | { "udf", 32, 1, 5, "NSR02", probe_udf }, | |
1439 | { "udf", 32, 1, 5, "NSR03", probe_udf }, | |
1440 | { "udf", 32, 1, 5, "TEA01", probe_udf }, | |
45a3fa87 TT |
1441 | { "iso9660", 32, 1, 5, "CD001", probe_iso9660 }, |
1442 | { "iso9660", 32, 9, 5, "CDROM", probe_iso9660 }, | |
09a2ef8d | 1443 | { "jfs", 32, 0, 4, "JFS1", probe_jfs }, |
c9bad3ce RC |
1444 | { "zfs", 8, 0, 8, "\0\0\x02\xf5\xb0\x07\xb1\x0c", probe_zfs }, |
1445 | { "zfs", 8, 0, 8, "\x0c\xb1\x07\xb0\xf5\x02\0\0", probe_zfs }, | |
1446 | { "zfs", 264, 0, 8, "\0\0\x02\xf5\xb0\x07\xb1\x0c", probe_zfs }, | |
1447 | { "zfs", 264, 0, 8, "\x0c\xb1\x07\xb0\xf5\x02\0\0", probe_zfs }, | |
69d74228 | 1448 | { "hfsplus", 1, 0, 2, "BD", probe_hfsplus }, |
9c460caa TT |
1449 | { "hfsplus", 1, 0, 2, "H+", probe_hfsplus }, |
1450 | { "hfsplus", 1, 0, 2, "HX", probe_hfsplus }, | |
1451 | { "hfs", 1, 0, 2, "BD", probe_hfs }, | |
50b380b4 TT |
1452 | { "ufs", 8, 0x55c, 4, "T\031\001\000", 0 }, |
1453 | { "hpfs", 8, 0, 4, "I\350\225\371", 0 }, | |
1454 | { "sysv", 0, 0x3f8, 4, "\020~\030\375", 0 }, | |
7369f0ce TT |
1455 | { "swap", 0, 0xff6, 10, "SWAP-SPACE", probe_swap0 }, |
1456 | { "swap", 0, 0xff6, 10, "SWAPSPACE2", probe_swap1 }, | |
abaa1124 KZ |
1457 | { "swsuspend", 0, 0xff6, 9, "S1SUSPEND", probe_swap1 }, |
1458 | { "swsuspend", 0, 0xff6, 9, "S2SUSPEND", probe_swap1 }, | |
31e2a754 | 1459 | { "swsuspend", 0, 0xff6, 9, "ULSUSPEND", probe_swap1 }, |
7369f0ce TT |
1460 | { "swap", 0, 0x1ff6, 10, "SWAP-SPACE", probe_swap0 }, |
1461 | { "swap", 0, 0x1ff6, 10, "SWAPSPACE2", probe_swap1 }, | |
abaa1124 KZ |
1462 | { "swsuspend", 0, 0x1ff6, 9, "S1SUSPEND", probe_swap1 }, |
1463 | { "swsuspend", 0, 0x1ff6, 9, "S2SUSPEND", probe_swap1 }, | |
31e2a754 | 1464 | { "swsuspend", 0, 0x1ff6, 9, "ULSUSPEND", probe_swap1 }, |
7369f0ce TT |
1465 | { "swap", 0, 0x3ff6, 10, "SWAP-SPACE", probe_swap0 }, |
1466 | { "swap", 0, 0x3ff6, 10, "SWAPSPACE2", probe_swap1 }, | |
abaa1124 KZ |
1467 | { "swsuspend", 0, 0x3ff6, 9, "S1SUSPEND", probe_swap1 }, |
1468 | { "swsuspend", 0, 0x3ff6, 9, "S2SUSPEND", probe_swap1 }, | |
31e2a754 | 1469 | { "swsuspend", 0, 0x3ff6, 9, "ULSUSPEND", probe_swap1 }, |
7369f0ce TT |
1470 | { "swap", 0, 0x7ff6, 10, "SWAP-SPACE", probe_swap0 }, |
1471 | { "swap", 0, 0x7ff6, 10, "SWAPSPACE2", probe_swap1 }, | |
abaa1124 KZ |
1472 | { "swsuspend", 0, 0x7ff6, 9, "S1SUSPEND", probe_swap1 }, |
1473 | { "swsuspend", 0, 0x7ff6, 9, "S2SUSPEND", probe_swap1 }, | |
31e2a754 | 1474 | { "swsuspend", 0, 0x7ff6, 9, "ULSUSPEND", probe_swap1 }, |
7369f0ce TT |
1475 | { "swap", 0, 0xfff6, 10, "SWAP-SPACE", probe_swap0 }, |
1476 | { "swap", 0, 0xfff6, 10, "SWAPSPACE2", probe_swap1 }, | |
abaa1124 KZ |
1477 | { "swsuspend", 0, 0xfff6, 9, "S1SUSPEND", probe_swap1 }, |
1478 | { "swsuspend", 0, 0xfff6, 9, "S2SUSPEND", probe_swap1 }, | |
31e2a754 | 1479 | { "swsuspend", 0, 0xfff6, 9, "ULSUSPEND", probe_swap1 }, |
2c92375e TT |
1480 | { "ocfs", 0, 8, 9, "OracleCFS", probe_ocfs }, |
1481 | { "ocfs2", 1, 0, 6, "OCFSV2", probe_ocfs2 }, | |
1482 | { "ocfs2", 2, 0, 6, "OCFSV2", probe_ocfs2 }, | |
1483 | { "ocfs2", 4, 0, 6, "OCFSV2", probe_ocfs2 }, | |
1484 | { "ocfs2", 8, 0, 6, "OCFSV2", probe_ocfs2 }, | |
e382a7ea | 1485 | { "crypt_LUKS", 0, 0, 6, "LUKS\xba\xbe", probe_luks }, |
f493d4e0 | 1486 | { "squashfs", 0, 0, 4, "sqsh", 0 }, |
5845efd1 | 1487 | { "squashfs", 0, 0, 4, "hsqs", 0 }, |
a451d92f ES |
1488 | { "lvm2pv", 0, 0x218, 8, "LVM2 001", probe_lvm2 }, |
1489 | { "lvm2pv", 0, 0x018, 8, "LVM2 001", probe_lvm2 }, | |
1490 | { "lvm2pv", 1, 0x018, 8, "LVM2 001", probe_lvm2 }, | |
1491 | { "lvm2pv", 1, 0x218, 8, "LVM2 001", probe_lvm2 }, | |
801b0053 | 1492 | { "btrfs", 64, 0x40, 8, "_BHRfS_M", probe_btrfs }, |
50b380b4 | 1493 | { NULL, 0, 0, 0, NULL, NULL } |
e12f2ae7 TT |
1494 | }; |
1495 | ||
e12f2ae7 TT |
1496 | /* |
1497 | * Verify that the data in dev is consistent with what is on the actual | |
1498 | * block device (using the devname field only). Normally this will be | |
1499 | * called when finding items in the cache, but for long running processes | |
1500 | * is also desirable to revalidate an item before use. | |
1501 | * | |
1502 | * If we are unable to revalidate the data, we return the old data and | |
1503 | * do not set the BLKID_BID_FL_VERIFIED flag on it. | |
1504 | */ | |
18d12963 | 1505 | blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev) |
e12f2ae7 | 1506 | { |
e12f2ae7 | 1507 | struct blkid_magic *id; |
ca749859 | 1508 | struct blkid_probe probe; |
ba5e3849 | 1509 | blkid_tag_iterate iter; |
ca749859 | 1510 | unsigned char *buf; |
ba5e3849 | 1511 | const char *type, *value; |
50b380b4 | 1512 | struct stat st; |
7ce08064 | 1513 | time_t diff, now; |
ca749859 | 1514 | int idx; |
e12f2ae7 TT |
1515 | |
1516 | if (!dev) | |
1517 | return NULL; | |
1518 | ||
7ce08064 TT |
1519 | now = time(0); |
1520 | diff = now - dev->bid_time; | |
e12f2ae7 | 1521 | |
492ea655 TT |
1522 | if (stat(dev->bid_name, &st) < 0) { |
1523 | DBG(DEBUG_PROBE, | |
1524 | printf("blkid_verify: error %s (%d) while " | |
1525 | "trying to stat %s\n", strerror(errno), errno, | |
1526 | dev->bid_name)); | |
1527 | open_err: | |
1528 | if ((errno == EPERM) || (errno == EACCES) || (errno == ENOENT)) { | |
1529 | /* We don't have read permission, just return cache data. */ | |
1530 | DBG(DEBUG_PROBE, printf("returning unverified data for %s\n", | |
1531 | dev->bid_name)); | |
1532 | return dev; | |
1533 | } | |
1534 | blkid_free_dev(dev); | |
1535 | return NULL; | |
1536 | } | |
1537 | ||
1538 | if ((now >= dev->bid_time) && | |
1539 | (st.st_mtime <= dev->bid_time) && | |
efc6f628 | 1540 | ((diff < BLKID_PROBE_MIN) || |
e324b250 TT |
1541 | (dev->bid_flags & BLKID_BID_FL_VERIFIED && |
1542 | diff < BLKID_PROBE_INTERVAL))) | |
e12f2ae7 TT |
1543 | return dev; |
1544 | ||
f0a22d0f | 1545 | DBG(DEBUG_PROBE, |
79e62409 | 1546 | printf("need to revalidate %s (cache time %lu, stat time %lu,\n\t" |
492ea655 | 1547 | "time since last check %lu)\n", |
79e62409 ES |
1548 | dev->bid_name, (unsigned long)dev->bid_time, |
1549 | (unsigned long)st.st_mtime, (unsigned long)diff)); | |
492ea655 TT |
1550 | |
1551 | if ((probe.fd = open(dev->bid_name, O_RDONLY)) < 0) { | |
1552 | DBG(DEBUG_PROBE, printf("blkid_verify: error %s (%d) while " | |
efc6f628 | 1553 | "opening %s\n", strerror(errno), errno, |
492ea655 TT |
1554 | dev->bid_name)); |
1555 | goto open_err; | |
e12f2ae7 TT |
1556 | } |
1557 | ||
ca749859 TT |
1558 | probe.cache = cache; |
1559 | probe.dev = dev; | |
1560 | probe.sbbuf = 0; | |
1561 | probe.buf = 0; | |
1562 | probe.buf_max = 0; | |
efc6f628 | 1563 | |
50b380b4 TT |
1564 | /* |
1565 | * Iterate over the type array. If we already know the type, | |
1566 | * then try that first. If it doesn't work, then blow away | |
1567 | * the type information, and try again. | |
efc6f628 | 1568 | * |
50b380b4 TT |
1569 | */ |
1570 | try_again: | |
1571 | type = 0; | |
50b380b4 TT |
1572 | if (!dev->bid_type || !strcmp(dev->bid_type, "mdraid")) { |
1573 | uuid_t uuid; | |
1574 | ||
ca749859 | 1575 | if (check_mdraid(probe.fd, uuid) == 0) { |
ba5e3849 | 1576 | set_uuid(dev, uuid, 0); |
50b380b4 TT |
1577 | type = "mdraid"; |
1578 | goto found_type; | |
1579 | } | |
1580 | } | |
e12f2ae7 | 1581 | for (id = type_array; id->bim_type; id++) { |
50b380b4 TT |
1582 | if (dev->bid_type && |
1583 | strcmp(id->bim_type, dev->bid_type)) | |
1584 | continue; | |
1585 | ||
1586 | idx = id->bim_kboff + (id->bim_sboff >> 10); | |
d1da14b5 | 1587 | buf = get_buffer(&probe, (__u64) idx << 10, 1024); |
ca749859 | 1588 | if (!buf) |
50b380b4 | 1589 | continue; |
e12f2ae7 | 1590 | |
c9bad3ce | 1591 | if (memcmp(id->bim_magic, buf + (id->bim_sboff & 0x3ff), |
50b380b4 TT |
1592 | id->bim_len)) |
1593 | continue; | |
1594 | ||
1595 | if ((id->bim_probe == NULL) || | |
ca749859 | 1596 | (id->bim_probe(&probe, id, buf) == 0)) { |
50b380b4 TT |
1597 | type = id->bim_type; |
1598 | goto found_type; | |
e12f2ae7 TT |
1599 | } |
1600 | } | |
1601 | ||
50b380b4 TT |
1602 | if (!id->bim_type && dev->bid_type) { |
1603 | /* | |
ba5e3849 | 1604 | * Zap the device filesystem information and try again |
50b380b4 | 1605 | */ |
0225face TT |
1606 | DBG(DEBUG_PROBE, |
1607 | printf("previous fs type %s not valid, " | |
1608 | "trying full probe\n", dev->bid_type)); | |
ba5e3849 TT |
1609 | iter = blkid_tag_iterate_begin(dev); |
1610 | while (blkid_tag_next(iter, &type, &value) == 0) | |
1611 | blkid_set_tag(dev, type, 0, 0); | |
1612 | blkid_tag_iterate_end(iter); | |
50b380b4 TT |
1613 | goto try_again; |
1614 | } | |
e12f2ae7 | 1615 | |
50b380b4 | 1616 | if (!dev->bid_type) { |
e12f2ae7 | 1617 | blkid_free_dev(dev); |
257ace82 TT |
1618 | dev = 0; |
1619 | goto found_type; | |
50b380b4 | 1620 | } |
c9bad3ce | 1621 | |
50b380b4 TT |
1622 | found_type: |
1623 | if (dev && type) { | |
1624 | dev->bid_devno = st.st_rdev; | |
1625 | dev->bid_time = time(0); | |
1626 | dev->bid_flags |= BLKID_BID_FL_VERIFIED; | |
ce72b862 | 1627 | cache->bic_flags |= BLKID_BIC_FL_CHANGED; |
50b380b4 | 1628 | |
79dd234a | 1629 | blkid_set_tag(dev, "TYPE", type, 0); |
c9bad3ce | 1630 | |
12b3c8ec | 1631 | DBG(DEBUG_PROBE, printf("%s: devno 0x%04llx, type %s\n", |
12a829dc | 1632 | dev->bid_name, (long long)st.st_rdev, type)); |
e12f2ae7 TT |
1633 | } |
1634 | ||
45e338f5 JM |
1635 | free(probe.sbbuf); |
1636 | free(probe.buf); | |
efc6f628 | 1637 | if (probe.fd >= 0) |
257ace82 | 1638 | close(probe.fd); |
e12f2ae7 | 1639 | |
e12f2ae7 | 1640 | return dev; |
e12f2ae7 TT |
1641 | } |
1642 | ||
78e2edf7 TT |
1643 | int blkid_known_fstype(const char *fstype) |
1644 | { | |
1645 | struct blkid_magic *id; | |
1646 | ||
1647 | for (id = type_array; id->bim_type; id++) { | |
1648 | if (strcmp(fstype, id->bim_type) == 0) | |
1649 | return 1; | |
1650 | } | |
1651 | return 0; | |
1652 | } | |
1653 | ||
e12f2ae7 TT |
1654 | #ifdef TEST_PROGRAM |
1655 | int main(int argc, char **argv) | |
1656 | { | |
7a603aa8 | 1657 | blkid_dev dev; |
50b380b4 | 1658 | blkid_cache cache; |
79dd234a | 1659 | int ret; |
e12f2ae7 TT |
1660 | |
1661 | if (argc != 2) { | |
1662 | fprintf(stderr, "Usage: %s device\n" | |
1663 | "Probe a single device to determine type\n", argv[0]); | |
1664 | exit(1); | |
1665 | } | |
79dd234a TT |
1666 | if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { |
1667 | fprintf(stderr, "%s: error creating cache (%d)\n", | |
1668 | argv[0], ret); | |
1669 | exit(1); | |
1670 | } | |
98999c39 | 1671 | dev = blkid_get_dev(cache, argv[1], BLKID_DEV_NORMAL); |
50b380b4 | 1672 | if (!dev) { |
e12f2ae7 | 1673 | printf("%s: %s has an unsupported type\n", argv[0], argv[1]); |
50b380b4 TT |
1674 | return (1); |
1675 | } | |
1e5630ab | 1676 | printf("TYPE='%s'\n", dev->bid_type ? dev->bid_type : "(null)"); |
50b380b4 | 1677 | if (dev->bid_label) |
1e5630ab | 1678 | printf("LABEL='%s'\n", dev->bid_label); |
50b380b4 | 1679 | if (dev->bid_uuid) |
1e5630ab | 1680 | printf("UUID='%s'\n", dev->bid_uuid); |
efc6f628 | 1681 | |
50b380b4 | 1682 | blkid_free_dev(dev); |
e12f2ae7 TT |
1683 | return (0); |
1684 | } | |
1685 | #endif |