2 * probe.c - identify a block device by its contents, and return a dev
3 * struct with the details
5 * Copyright (C) 1999 by Andries Brouwer
6 * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
7 * Copyright (C) 2001 by Andreas Dilger
8 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
11 * This file may be redistributed under the terms of the
12 * GNU Lesser General Public License.
22 #include <sys/types.h>
23 #ifdef HAVE_SYS_STAT_H
26 #ifdef HAVE_SYS_MKDEV_H
27 #include <sys/mkdev.h>
29 #include <sys/utsname.h>
34 #include "uuid/uuid.h"
37 static int figure_label_len(const unsigned char *label
, int len
)
39 const unsigned char *end
= label
+ len
- 1;
41 while ((*end
== ' ' || *end
== 0) && end
>= label
)
45 return end
- label
+ 1;
50 static unsigned char *get_buffer(struct blkid_probe
*pr
,
51 blkid_loff_t off
, size_t len
)
54 unsigned char *newbuf
;
56 if (off
+ len
<= SB_BUFFER_SIZE
) {
58 pr
->sbbuf
= malloc(SB_BUFFER_SIZE
);
61 if (lseek(pr
->fd
, 0, SEEK_SET
) < 0)
63 ret_read
= read(pr
->fd
, pr
->sbbuf
, SB_BUFFER_SIZE
);
66 pr
->sb_valid
= ret_read
;
68 if (off
+len
> pr
->sb_valid
)
70 return pr
->sbbuf
+ off
;
72 if (len
> pr
->buf_max
) {
73 newbuf
= realloc(pr
->buf
, len
);
79 if (blkid_llseek(pr
->fd
, off
, SEEK_SET
) < 0)
81 ret_read
= read(pr
->fd
, pr
->buf
, len
);
82 if (ret_read
!= (ssize_t
) len
)
90 * This is a special case code to check for an MDRAID device. We do
91 * this special since it requires checking for a superblock at the end
94 static int check_mdraid(int fd
, unsigned char *ret_uuid
)
96 struct mdp_superblock_s
*md
;
101 return -BLKID_ERR_PARAM
;
103 offset
= (blkid_get_dev_size(fd
) & ~((blkid_loff_t
)65535)) - 65536;
105 if (blkid_llseek(fd
, offset
, 0) < 0 ||
106 read(fd
, buf
, 4096) != 4096)
107 return -BLKID_ERR_IO
;
109 /* Check for magic number */
110 if (memcmp("\251+N\374", buf
, 4) && memcmp("\374N+\251", buf
, 4))
111 return -BLKID_ERR_PARAM
;
117 /* The MD UUID is not contiguous in the superblock, make it so */
118 md
= (struct mdp_superblock_s
*)buf
;
119 if (md
->set_uuid0
|| md
->set_uuid1
|| md
->set_uuid2
|| md
->set_uuid3
) {
120 memcpy(ret_uuid
, &md
->set_uuid0
, 4);
121 memcpy(ret_uuid
+ 4, &md
->set_uuid1
, 12);
126 static void set_uuid(blkid_dev dev
, uuid_t uuid
, const char *tag
)
130 if (!uuid_is_null(uuid
)) {
131 uuid_unparse(uuid
, str
);
132 blkid_set_tag(dev
, tag
? tag
: "UUID", str
, sizeof(str
));
136 static void get_ext2_info(blkid_dev dev
, struct blkid_magic
*id
,
139 struct ext2_super_block
*es
= (struct ext2_super_block
*) buf
;
140 const char *label
= 0;
142 DBG(DEBUG_PROBE
, printf("ext2_sb.compat = %08X:%08X:%08X\n",
143 blkid_le32(es
->s_feature_compat
),
144 blkid_le32(es
->s_feature_incompat
),
145 blkid_le32(es
->s_feature_ro_compat
)));
147 if (strlen(es
->s_volume_name
))
148 label
= es
->s_volume_name
;
149 blkid_set_tag(dev
, "LABEL", label
, sizeof(es
->s_volume_name
));
151 set_uuid(dev
, es
->s_uuid
, 0);
153 if ((es
->s_feature_compat
& EXT3_FEATURE_COMPAT_HAS_JOURNAL
) &&
154 !uuid_is_null(es
->s_journal_uuid
))
155 set_uuid(dev
, es
->s_journal_uuid
, "EXT_JOURNAL");
157 if (strcmp(id
->bim_type
, "ext2") &&
158 ((blkid_le32(es
->s_feature_incompat
) &
159 EXT2_FEATURE_INCOMPAT_UNSUPPORTED
) == 0))
160 blkid_set_tag(dev
, "SEC_TYPE", "ext2", sizeof("ext2"));
164 * Check to see if a filesystem is in /proc/filesystems.
165 * Returns 1 if found, 0 if not
167 static int fs_proc_check(const char *fs_name
)
170 char buf
[80], *cp
, *t
;
172 f
= fopen("/proc/filesystems", "r");
176 if (!fgets(buf
, sizeof(buf
), f
))
180 while (*cp
&& !isspace(*cp
))
183 while (*cp
&& isspace(*cp
))
185 if ((t
= strchr(cp
, '\n')) != NULL
)
187 if ((t
= strchr(cp
, '\t')) != NULL
)
189 if ((t
= strchr(cp
, ' ')) != NULL
)
191 if (!strcmp(fs_name
, cp
)) {
201 * Check to see if a filesystem is available as a module
202 * Returns 1 if found, 0 if not
204 static int check_for_modules(const char *fs_name
)
208 char buf
[1024], *cp
, *t
;
213 snprintf(buf
, sizeof(buf
), "/lib/modules/%s/modules.dep", uts
.release
);
219 if (!fgets(buf
, sizeof(buf
), f
))
221 if ((cp
= strchr(buf
, ':')) != NULL
)
225 if ((cp
= strrchr(buf
, '/')) != NULL
)
230 if (!strcmp(t
, ".ko"))
233 if (!strcmp(cp
, fs_name
))
240 static int system_supports_ext4(void)
242 static time_t last_check
= 0;
244 time_t now
= time(0);
246 if (ret
!= -1 || (last_check
- now
) < 5)
249 ret
= (fs_proc_check("ext4") || check_for_modules("ext4"));
253 static int system_supports_ext4dev(void)
255 static time_t last_check
= 0;
257 time_t now
= time(0);
259 if (ret
!= -1 || (last_check
- now
) < 5)
262 ret
= (fs_proc_check("ext4dev") || check_for_modules("ext4dev"));
266 static int probe_ext4dev(struct blkid_probe
*probe
,
267 struct blkid_magic
*id
,
270 struct ext2_super_block
*es
;
271 es
= (struct ext2_super_block
*)buf
;
273 /* Distinguish from jbd */
274 if (blkid_le32(es
->s_feature_incompat
) &
275 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV
)
276 return -BLKID_ERR_PARAM
;
278 /* ext4dev requires a journal */
279 if (!(blkid_le32(es
->s_feature_compat
) &
280 EXT3_FEATURE_COMPAT_HAS_JOURNAL
))
281 return -BLKID_ERR_PARAM
;
284 * If the filesystem is marked as OK for use by in-development
285 * filesystem code, but ext4dev is not supported, and ext4 is,
286 * then don't call ourselves ext4dev, since we should be
287 * detected as ext4 in that case.
289 * If the filesystem is marked as in use by production
290 * filesystem, then it can only be used by ext4 and NOT by
291 * ext4dev, so always disclaim we are ext4dev in that case.
293 if (blkid_le32(es
->s_flags
) & EXT2_FLAGS_TEST_FILESYS
) {
294 if (!system_supports_ext4dev() && system_supports_ext4())
295 return -BLKID_ERR_PARAM
;
297 return -BLKID_ERR_PARAM
;
299 get_ext2_info(probe
->dev
, id
, buf
);
303 static int probe_ext4(struct blkid_probe
*probe
, struct blkid_magic
*id
,
306 struct ext2_super_block
*es
;
307 es
= (struct ext2_super_block
*)buf
;
309 /* Distinguish from jbd */
310 if (blkid_le32(es
->s_feature_incompat
) &
311 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV
)
312 return -BLKID_ERR_PARAM
;
314 /* ext4 requires journal */
315 if (!(blkid_le32(es
->s_feature_compat
) &
316 EXT3_FEATURE_COMPAT_HAS_JOURNAL
))
317 return -BLKID_ERR_PARAM
;
319 /* Ext4 has at least one feature which ext3 doesn't understand */
320 if (!(blkid_le32(es
->s_feature_ro_compat
) &
321 EXT3_FEATURE_RO_COMPAT_UNSUPPORTED
) &&
322 !(blkid_le32(es
->s_feature_incompat
) &
323 EXT3_FEATURE_INCOMPAT_UNSUPPORTED
))
324 return -BLKID_ERR_PARAM
;
327 * If the filesystem is a OK for use by in-development
328 * filesystem code, and ext4dev is supported or ext4 is not
329 * supported, then don't call ourselves ext4, so we can redo
330 * the detection and mark the filesystem as ext4dev.
332 * If the filesystem is marked as in use by production
333 * filesystem, then it can only be used by ext4 and NOT by
336 if (blkid_le32(es
->s_flags
) & EXT2_FLAGS_TEST_FILESYS
) {
337 if (system_supports_ext4dev() || !system_supports_ext4())
338 return -BLKID_ERR_PARAM
;
340 get_ext2_info(probe
->dev
, id
, buf
);
344 static int probe_ext3(struct blkid_probe
*probe
, struct blkid_magic
*id
,
347 struct ext2_super_block
*es
;
348 es
= (struct ext2_super_block
*)buf
;
350 /* Distinguish from ext4dev */
351 if (blkid_le32(es
->s_flags
) & EXT2_FLAGS_TEST_FILESYS
)
352 return -BLKID_ERR_PARAM
;
354 /* ext3 requires journal */
355 if (!(blkid_le32(es
->s_feature_compat
) &
356 EXT3_FEATURE_COMPAT_HAS_JOURNAL
))
357 return -BLKID_ERR_PARAM
;
359 /* Any features which ext3 doesn't understand */
360 if ((blkid_le32(es
->s_feature_ro_compat
) &
361 EXT3_FEATURE_RO_COMPAT_UNSUPPORTED
) ||
362 (blkid_le32(es
->s_feature_incompat
) &
363 EXT3_FEATURE_INCOMPAT_UNSUPPORTED
))
364 return -BLKID_ERR_PARAM
;
366 get_ext2_info(probe
->dev
, id
, buf
);
370 static int probe_ext2(struct blkid_probe
*probe
, struct blkid_magic
*id
,
373 struct ext2_super_block
*es
;
375 es
= (struct ext2_super_block
*)buf
;
377 /* Distinguish between ext3 and ext2 */
378 if ((blkid_le32(es
->s_feature_compat
) &
379 EXT3_FEATURE_COMPAT_HAS_JOURNAL
))
380 return -BLKID_ERR_PARAM
;
382 /* Any features which ext2 doesn't understand */
383 if ((blkid_le32(es
->s_feature_ro_compat
) &
384 EXT2_FEATURE_RO_COMPAT_UNSUPPORTED
) ||
385 (blkid_le32(es
->s_feature_incompat
) &
386 EXT2_FEATURE_INCOMPAT_UNSUPPORTED
))
387 return -BLKID_ERR_PARAM
;
389 get_ext2_info(probe
->dev
, id
, buf
);
393 static int probe_jbd(struct blkid_probe
*probe
, struct blkid_magic
*id
,
396 struct ext2_super_block
*es
= (struct ext2_super_block
*) buf
;
398 if (!(blkid_le32(es
->s_feature_incompat
) &
399 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV
))
400 return -BLKID_ERR_PARAM
;
402 get_ext2_info(probe
->dev
, id
, buf
);
407 #define FAT_ATTR_VOLUME_ID 0x08
408 #define FAT_ATTR_DIR 0x10
409 #define FAT_ATTR_LONG_NAME 0x0f
410 #define FAT_ATTR_MASK 0x3f
411 #define FAT_ENTRY_FREE 0xe5
413 static const char *no_name
= "NO NAME ";
415 static unsigned char *search_fat_label(struct vfat_dir_entry
*dir
, int count
)
419 for (i
= 0; i
< count
; i
++) {
420 if (dir
[i
].name
[0] == 0x00)
423 if ((dir
[i
].name
[0] == FAT_ENTRY_FREE
) ||
424 (dir
[i
].cluster_high
!= 0 || dir
[i
].cluster_low
!= 0) ||
425 ((dir
[i
].attr
& FAT_ATTR_MASK
) == FAT_ATTR_LONG_NAME
))
428 if ((dir
[i
].attr
& (FAT_ATTR_VOLUME_ID
| FAT_ATTR_DIR
)) ==
429 FAT_ATTR_VOLUME_ID
) {
436 /* FAT label extraction from the root directory taken from Kay
437 * Sievers's volume_id library */
438 static int probe_fat(struct blkid_probe
*probe
,
439 struct blkid_magic
*id
__BLKID_ATTR((unused
)),
442 struct vfat_super_block
*vs
= (struct vfat_super_block
*) buf
;
443 struct msdos_super_block
*ms
= (struct msdos_super_block
*) buf
;
444 struct vfat_dir_entry
*dir
;
446 const unsigned char *label
= 0, *vol_label
= 0, *tmp
;
447 unsigned char *vol_serno
;
448 int label_len
= 0, maxloop
= 100;
449 __u16 sector_size
, dir_entries
, reserved
;
450 __u32 sect_count
, fat_size
, dir_size
, cluster_count
, fat_length
;
451 __u32 buf_size
, start_data_sect
, next
, root_start
, root_dir_entries
;
453 /* sector size check */
454 tmp
= (unsigned char *)&ms
->ms_sector_size
;
455 sector_size
= tmp
[0] + (tmp
[1] << 8);
456 if (sector_size
!= 0x200 && sector_size
!= 0x400 &&
457 sector_size
!= 0x800 && sector_size
!= 0x1000)
460 tmp
= (unsigned char *)&ms
->ms_dir_entries
;
461 dir_entries
= tmp
[0] + (tmp
[1] << 8);
462 reserved
= blkid_le16(ms
->ms_reserved
);
463 tmp
= (unsigned char *)&ms
->ms_sectors
;
464 sect_count
= tmp
[0] + (tmp
[1] << 8);
466 sect_count
= blkid_le32(ms
->ms_total_sect
);
468 fat_length
= blkid_le16(ms
->ms_fat_length
);
470 fat_length
= blkid_le32(vs
->vs_fat32_length
);
472 fat_size
= fat_length
* ms
->ms_fats
;
473 dir_size
= ((dir_entries
* sizeof(struct vfat_dir_entry
)) +
474 (sector_size
-1)) / sector_size
;
476 cluster_count
= sect_count
- (reserved
+ fat_size
+ dir_size
);
477 if (ms
->ms_cluster_size
== 0)
479 cluster_count
/= ms
->ms_cluster_size
;
481 if (cluster_count
> FAT32_MAX
)
484 if (ms
->ms_fat_length
) {
485 /* the label may be an attribute in the root directory */
486 root_start
= (reserved
+ fat_size
) * sector_size
;
487 root_dir_entries
= vs
->vs_dir_entries
[0] +
488 (vs
->vs_dir_entries
[1] << 8);
490 buf_size
= root_dir_entries
* sizeof(struct vfat_dir_entry
);
491 dir
= (struct vfat_dir_entry
*) get_buffer(probe
, root_start
,
494 vol_label
= search_fat_label(dir
, root_dir_entries
);
496 if (!vol_label
|| !memcmp(vol_label
, no_name
, 11))
497 vol_label
= ms
->ms_label
;
498 vol_serno
= ms
->ms_serno
;
500 blkid_set_tag(probe
->dev
, "SEC_TYPE", "msdos",
503 /* Search the FAT32 root dir for the label attribute */
504 buf_size
= vs
->vs_cluster_size
* sector_size
;
505 start_data_sect
= reserved
+ fat_size
;
507 next
= blkid_le32(vs
->vs_root_cluster
);
508 while (next
&& --maxloop
) {
510 __u64 next_off
, fat_entry_off
;
513 next_sect_off
= (next
- 2) * vs
->vs_cluster_size
;
514 next_off
= (start_data_sect
+ next_sect_off
) *
517 dir
= (struct vfat_dir_entry
*)
518 get_buffer(probe
, next_off
, buf_size
);
522 count
= buf_size
/ sizeof(struct vfat_dir_entry
);
524 vol_label
= search_fat_label(dir
, count
);
529 fat_entry_off
= (reserved
* sector_size
) +
530 (next
* sizeof(__u32
));
531 buf
= get_buffer(probe
, fat_entry_off
, buf_size
);
535 /* set next cluster */
536 next
= blkid_le32(*((__u32
*) buf
) & 0x0fffffff);
539 if (!vol_label
|| !memcmp(vol_label
, no_name
, 11))
540 vol_label
= vs
->vs_label
;
541 vol_serno
= vs
->vs_serno
;
544 if (vol_label
&& memcmp(vol_label
, no_name
, 11)) {
545 if ((label_len
= figure_label_len(vol_label
, 11)))
549 /* We can't just print them as %04X, because they are unaligned */
550 sprintf(serno
, "%02X%02X-%02X%02X", vol_serno
[3], vol_serno
[2],
551 vol_serno
[1], vol_serno
[0]);
553 blkid_set_tag(probe
->dev
, "LABEL", (const char *) label
, label_len
);
554 blkid_set_tag(probe
->dev
, "UUID", serno
, sizeof(serno
)-1);
560 * The FAT filesystem could be without a magic string in superblock
561 * (e.g. old floppies). This heuristic for FAT detection is inspired
562 * by http://vrfy.org/projects/volume_id/ and Linux kernel.
563 * [7-Jul-2005, Karel Zak <kzak@redhat.com>]
565 static int probe_fat_nomagic(struct blkid_probe
*probe
,
566 struct blkid_magic
*id
__BLKID_ATTR((unused
)),
569 struct vfat_super_block
*vs
;
571 vs
= (struct vfat_super_block
*)buf
;
574 if (vs
->vs_heads
== 0)
577 /* cluster size check*/
578 if (vs
->vs_cluster_size
== 0 ||
579 (vs
->vs_cluster_size
& (vs
->vs_cluster_size
-1)))
583 if (vs
->vs_media
< 0xf8 && vs
->vs_media
!= 0xf0)
586 /* fat counts(Linux kernel expects at least 1 FAT table) */
590 return probe_fat(probe
, id
, buf
);
593 static int probe_ntfs(struct blkid_probe
*probe
,
594 struct blkid_magic
*id
__BLKID_ATTR((unused
)),
597 struct ntfs_super_block
*ns
;
598 struct master_file_table_record
*mft
;
599 struct file_attribute
*attr
;
600 char uuid_str
[17], label_str
[129], *cp
;
601 int bytes_per_sector
, sectors_per_cluster
;
602 int mft_record_size
, attr_off
, attr_len
;
603 unsigned int i
, attr_type
, val_len
;
607 unsigned char *buf_mft
, *val
;
609 ns
= (struct ntfs_super_block
*) buf
;
611 bytes_per_sector
= ns
->bios_parameter_block
[0] +
612 (ns
->bios_parameter_block
[1] << 8);
613 sectors_per_cluster
= ns
->bios_parameter_block
[2];
615 if ((bytes_per_sector
< 512) || (sectors_per_cluster
== 0))
618 if (ns
->cluster_per_mft_record
< 0)
619 mft_record_size
= 1 << (0-ns
->cluster_per_mft_record
);
621 mft_record_size
= ns
->cluster_per_mft_record
*
622 sectors_per_cluster
* bytes_per_sector
;
623 nr_clusters
= blkid_le64(ns
->number_of_sectors
) / sectors_per_cluster
;
625 if ((blkid_le64(ns
->mft_cluster_location
) > nr_clusters
) ||
626 (blkid_le64(ns
->mft_mirror_cluster_location
) > nr_clusters
))
629 off
= blkid_le64(ns
->mft_mirror_cluster_location
) *
630 bytes_per_sector
* sectors_per_cluster
;
632 buf_mft
= get_buffer(probe
, off
, mft_record_size
);
636 if (memcmp(buf_mft
, "FILE", 4))
639 off
= blkid_le64(ns
->mft_cluster_location
) * bytes_per_sector
*
642 buf_mft
= get_buffer(probe
, off
, mft_record_size
);
646 if (memcmp(buf_mft
, "FILE", 4))
649 off
+= MFT_RECORD_VOLUME
* mft_record_size
;
651 buf_mft
= get_buffer(probe
, off
, mft_record_size
);
655 if (memcmp(buf_mft
, "FILE", 4))
658 mft
= (struct master_file_table_record
*) buf_mft
;
660 attr_off
= blkid_le16(mft
->attrs_offset
);
664 attr
= (struct file_attribute
*) (buf_mft
+ attr_off
);
665 attr_len
= blkid_le16(attr
->len
);
666 attr_type
= blkid_le32(attr
->type
);
667 val_off
= blkid_le16(attr
->value_offset
);
668 val_len
= blkid_le32(attr
->value_len
);
670 attr_off
+= attr_len
;
672 if ((attr_off
> mft_record_size
) ||
676 if (attr_type
== MFT_RECORD_ATTR_END
)
679 if (attr_type
== MFT_RECORD_ATTR_VOLUME_NAME
) {
680 if (val_len
> sizeof(label_str
))
681 val_len
= sizeof(label_str
)-1;
683 for (i
=0, cp
=label_str
; i
< val_len
; i
+=2,cp
++) {
684 val
= ((__u8
*) attr
) + val_off
+ i
;
693 sprintf(uuid_str
, "%016llX", blkid_le64(ns
->volume_serial
));
694 blkid_set_tag(probe
->dev
, "UUID", uuid_str
, 0);
696 blkid_set_tag(probe
->dev
, "LABEL", label_str
, 0);
701 static int probe_xfs(struct blkid_probe
*probe
,
702 struct blkid_magic
*id
__BLKID_ATTR((unused
)),
705 struct xfs_super_block
*xs
;
706 const char *label
= 0;
708 xs
= (struct xfs_super_block
*)buf
;
710 if (strlen(xs
->xs_fname
))
711 label
= xs
->xs_fname
;
712 blkid_set_tag(probe
->dev
, "LABEL", label
, sizeof(xs
->xs_fname
));
713 set_uuid(probe
->dev
, xs
->xs_uuid
, 0);
717 static int probe_reiserfs(struct blkid_probe
*probe
,
718 struct blkid_magic
*id
, unsigned char *buf
)
720 struct reiserfs_super_block
*rs
= (struct reiserfs_super_block
*) buf
;
721 unsigned int blocksize
;
722 const char *label
= 0;
724 blocksize
= blkid_le16(rs
->rs_blocksize
);
726 /* The blocksize must be at least 1k */
727 if ((blocksize
>> 10) == 0)
728 return -BLKID_ERR_PARAM
;
730 /* If the superblock is inside the journal, we have the wrong one */
731 if (id
->bim_kboff
/(blocksize
>>10) > blkid_le32(rs
->rs_journal_block
))
732 return -BLKID_ERR_BIG
;
734 /* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */
735 if (id
->bim_magic
[6] == '2' || id
->bim_magic
[6] == '3') {
736 if (strlen(rs
->rs_label
))
737 label
= rs
->rs_label
;
738 set_uuid(probe
->dev
, rs
->rs_uuid
, 0);
740 blkid_set_tag(probe
->dev
, "LABEL", label
, sizeof(rs
->rs_label
));
745 static int probe_reiserfs4(struct blkid_probe
*probe
,
746 struct blkid_magic
*id
__BLKID_ATTR((unused
)),
749 struct reiser4_super_block
*rs4
= (struct reiser4_super_block
*) buf
;
750 const unsigned char *label
= 0;
752 if (strlen((char *) rs4
->rs4_label
))
753 label
= rs4
->rs4_label
;
754 set_uuid(probe
->dev
, rs4
->rs4_uuid
, 0);
755 blkid_set_tag(probe
->dev
, "LABEL", (const char *) label
,
756 sizeof(rs4
->rs4_label
));
761 static int probe_jfs(struct blkid_probe
*probe
,
762 struct blkid_magic
*id
__BLKID_ATTR((unused
)),
765 struct jfs_super_block
*js
;
766 const char *label
= 0;
768 js
= (struct jfs_super_block
*)buf
;
770 if (strlen((char *) js
->js_label
))
771 label
= (char *) js
->js_label
;
772 blkid_set_tag(probe
->dev
, "LABEL", label
, sizeof(js
->js_label
));
773 set_uuid(probe
->dev
, js
->js_uuid
, 0);
777 static int probe_luks(struct blkid_probe
*probe
,
778 struct blkid_magic
*id
__BLKID_ATTR((unused
)),
782 /* 168 is the offset to the 40 character uuid:
783 * http://luks.endorphin.org/LUKS-on-disk-format.pdf */
784 strncpy(uuid
, (char *) buf
+168, 40);
785 blkid_set_tag(probe
->dev
, "UUID", uuid
, sizeof(uuid
));
789 static int probe_romfs(struct blkid_probe
*probe
,
790 struct blkid_magic
*id
__BLKID_ATTR((unused
)),
793 struct romfs_super_block
*ros
;
794 const char *label
= 0;
796 ros
= (struct romfs_super_block
*)buf
;
798 if (strlen((char *) ros
->ros_volume
))
799 label
= (char *) ros
->ros_volume
;
800 blkid_set_tag(probe
->dev
, "LABEL", label
, 0);
804 static int probe_cramfs(struct blkid_probe
*probe
,
805 struct blkid_magic
*id
__BLKID_ATTR((unused
)),
808 struct cramfs_super_block
*csb
;
809 const char *label
= 0;
811 csb
= (struct cramfs_super_block
*)buf
;
813 if (strlen((char *) csb
->name
))
814 label
= (char *) csb
->name
;
815 blkid_set_tag(probe
->dev
, "LABEL", label
, 0);
819 static int probe_swap0(struct blkid_probe
*probe
,
820 struct blkid_magic
*id
__BLKID_ATTR((unused
)),
821 unsigned char *buf
__BLKID_ATTR((unused
)))
823 blkid_set_tag(probe
->dev
, "UUID", 0, 0);
824 blkid_set_tag(probe
->dev
, "LABEL", 0, 0);
828 static int probe_swap1(struct blkid_probe
*probe
,
829 struct blkid_magic
*id
__BLKID_ATTR((unused
)),
830 unsigned char *buf
__BLKID_ATTR((unused
)))
832 struct swap_id_block
*sws
;
834 probe_swap0(probe
, id
, buf
);
836 * Version 1 swap headers are always located at offset of 1024
837 * bytes, although the swap signature itself is located at the
838 * end of the page (which may vary depending on hardware
841 sws
= (struct swap_id_block
*) get_buffer(probe
, 1024, 1024);
845 /* arbitrary sanity check.. is there any garbage down there? */
846 if (sws
->sws_pad
[32] == 0 && sws
->sws_pad
[33] == 0) {
847 if (sws
->sws_volume
[0])
848 blkid_set_tag(probe
->dev
, "LABEL", sws
->sws_volume
,
849 sizeof(sws
->sws_volume
));
850 if (sws
->sws_uuid
[0])
851 set_uuid(probe
->dev
, sws
->sws_uuid
, 0);
856 static int probe_iso9660(struct blkid_probe
*probe
,
857 struct blkid_magic
*id
__BLKID_ATTR((unused
)),
860 struct iso_volume_descriptor
*iso
;
861 const unsigned char *label
;
863 iso
= (struct iso_volume_descriptor
*) buf
;
864 label
= iso
->volume_id
;
866 blkid_set_tag(probe
->dev
, "LABEL", (const char *) label
,
867 figure_label_len(label
, 32));
873 *udf_magic
[] = { "BEA01", "BOOT2", "CD001", "CDW02", "NSR02",
874 "NSR03", "TEA01", 0 };
876 static int probe_udf(struct blkid_probe
*probe
,
877 struct blkid_magic
*id
__BLKID_ATTR((unused
)),
878 unsigned char *buf
__BLKID_ATTR((unused
)))
881 struct iso_volume_descriptor
*isosb
;
884 /* determine the block size by scanning in 2K increments
885 (block sizes larger than 2K will be null padded) */
886 for (bs
= 1; bs
< 16; bs
++) {
887 isosb
= (struct iso_volume_descriptor
*)
888 get_buffer(probe
, bs
*2048+32768, sizeof(isosb
));
895 /* Scan up to another 64 blocks looking for additional VSD's */
896 for (j
= 1; j
< 64; j
++) {
898 isosb
= (struct iso_volume_descriptor
*)
899 get_buffer(probe
, j
*bs
*2048+32768,
904 /* If we find NSR0x then call it udf:
907 NSR03 for UDF 2.00 */
908 if (!memcmp(isosb
->vd_id
, "NSR0", 4))
909 return probe_iso9660(probe
, id
, buf
);
910 for (m
= udf_magic
; *m
; m
++)
911 if (!memcmp(*m
, isosb
->vd_id
, 5))
919 static int probe_ocfs(struct blkid_probe
*probe
,
920 struct blkid_magic
*id
__BLKID_ATTR((unused
)),
923 struct ocfs_volume_header ovh
;
924 struct ocfs_volume_label ovl
;
927 memcpy(&ovh
, buf
, sizeof(ovh
));
928 memcpy(&ovl
, buf
+512, sizeof(ovl
));
930 major
= ocfsmajor(ovh
);
932 blkid_set_tag(probe
->dev
,"SEC_TYPE","ocfs1",sizeof("ocfs1"));
934 blkid_set_tag(probe
->dev
,"SEC_TYPE","ntocfs",sizeof("ntocfs"));
936 blkid_set_tag(probe
->dev
, "LABEL", ovl
.label
, ocfslabellen(ovl
));
937 blkid_set_tag(probe
->dev
, "MOUNT", ovh
.mount
, ocfsmountlen(ovh
));
938 set_uuid(probe
->dev
, ovl
.vol_id
, 0);
942 static int probe_ocfs2(struct blkid_probe
*probe
,
943 struct blkid_magic
*id
__BLKID_ATTR((unused
)),
946 struct ocfs2_super_block
*osb
;
948 osb
= (struct ocfs2_super_block
*)buf
;
950 blkid_set_tag(probe
->dev
, "LABEL", osb
->s_label
, sizeof(osb
->s_label
));
951 set_uuid(probe
->dev
, osb
->s_uuid
, 0);
955 static int probe_oracleasm(struct blkid_probe
*probe
,
956 struct blkid_magic
*id
__BLKID_ATTR((unused
)),
959 struct oracle_asm_disk_label
*dl
;
961 dl
= (struct oracle_asm_disk_label
*)buf
;
963 blkid_set_tag(probe
->dev
, "LABEL", dl
->dl_id
, sizeof(dl
->dl_id
));
967 static int probe_gfs(struct blkid_probe
*probe
,
968 struct blkid_magic
*id
__BLKID_ATTR((unused
)),
972 const char *label
= 0;
974 sbd
= (struct gfs2_sb
*)buf
;
976 if (blkid_be32(sbd
->sb_fs_format
) == GFS_FORMAT_FS
&&
977 blkid_be32(sbd
->sb_multihost_format
) == GFS_FORMAT_MULTI
)
979 blkid_set_tag(probe
->dev
, "UUID", 0, 0);
981 if (strlen(sbd
->sb_locktable
))
982 label
= sbd
->sb_locktable
;
983 blkid_set_tag(probe
->dev
, "LABEL", label
, sizeof(sbd
->sb_locktable
));
989 static int probe_gfs2(struct blkid_probe
*probe
,
990 struct blkid_magic
*id
__BLKID_ATTR((unused
)),
994 const char *label
= 0;
996 sbd
= (struct gfs2_sb
*)buf
;
998 if (blkid_be32(sbd
->sb_fs_format
) == GFS2_FORMAT_FS
&&
999 blkid_be32(sbd
->sb_multihost_format
) == GFS2_FORMAT_MULTI
)
1001 blkid_set_tag(probe
->dev
, "UUID", 0, 0);
1003 if (strlen(sbd
->sb_locktable
))
1004 label
= sbd
->sb_locktable
;
1005 blkid_set_tag(probe
->dev
, "LABEL", label
, sizeof(sbd
->sb_locktable
));
1011 static int probe_hfsplus(struct blkid_probe
*probe
__BLKID_ATTR((unused
)),
1012 struct blkid_magic
*id
__BLKID_ATTR((unused
)),
1015 struct hfs_mdb
*sbd
= (struct hfs_mdb
*)buf
;
1017 /* Check for a HFS+ volume embedded in a HFS volume */
1018 if (memcmp(sbd
->embed_sig
, "H+", 2) == 0)
1024 #define LVM2_LABEL_SIZE 512
1025 static unsigned int lvm2_calc_crc(const void *buf
, uint size
)
1027 static const uint crctab
[] = {
1028 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
1029 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
1030 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
1031 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
1033 uint i
, crc
= 0xf597a6cf;
1034 const __u8
*data
= (const __u8
*) buf
;
1036 for (i
= 0; i
< size
; i
++) {
1038 crc
= (crc
>> 4) ^ crctab
[crc
& 0xf];
1039 crc
= (crc
>> 4) ^ crctab
[crc
& 0xf];
1044 static int probe_lvm2(struct blkid_probe
*probe
,
1045 struct blkid_magic
*id
__BLKID_ATTR((unused
)),
1048 int sector
= (id
->bim_kboff
) << 1;;
1049 struct lvm2_pv_label_header
*label
;
1050 label
= (struct lvm2_pv_label_header
*)buf
;
1051 char *p
, *q
, uuid
[40];
1054 /* buf is at 0k or 1k offset; find label inside */
1055 if (memcmp(buf
, "LABELONE", 8) == 0) {
1056 label
= (struct lvm2_pv_label_header
*)buf
;
1057 } else if (memcmp(buf
+ 512, "LABELONE", 8) == 0) {
1058 label
= (struct lvm2_pv_label_header
*)(buf
+ 512);
1064 if (blkid_le64(label
->sector_xl
) != (unsigned) sector
) {
1066 printf("LVM2: label for sector %llu found at sector %d\n",
1067 blkid_le64(label
->sector_xl
), sector
));
1071 if (lvm2_calc_crc(&label
->offset_xl
, LVM2_LABEL_SIZE
-
1072 ((char *)&label
->offset_xl
- (char *)label
)) !=
1073 blkid_le32(label
->crc_xl
)) {
1075 printf("LVM2: label checksum incorrect at sector %d\n",
1080 for (i
=0, b
=1, p
=uuid
, q
= (char *) label
->pv_uuid
; i
<= 32;
1087 blkid_set_tag(probe
->dev
, "UUID", uuid
, LVM2_ID_LEN
+6);
1092 * BLKID_BLK_OFFS is at least as large as the highest bim_kboff defined
1093 * in the type_array table below + bim_kbalign.
1095 * When probing for a lot of magics, we handle everything in 1kB buffers so
1096 * that we don't have to worry about reading each combination of block sizes.
1098 #define BLKID_BLK_OFFS 64 /* currently reiserfs */
1101 * Various filesystem magics that we can check for. Note that kboff and
1102 * sboff are in kilobytes and bytes respectively. All magics are in
1103 * byte strings so we don't worry about endian issues.
1105 static struct blkid_magic type_array
[] = {
1106 /* type kboff sboff len magic probe */
1107 { "oracleasm", 0, 32, 8, "ORCLDISK", probe_oracleasm
},
1108 { "ntfs", 0, 3, 8, "NTFS ", probe_ntfs
},
1109 { "jbd", 1, 0x38, 2, "\123\357", probe_jbd
},
1110 { "ext4dev", 1, 0x38, 2, "\123\357", probe_ext4dev
},
1111 { "ext4", 1, 0x38, 2, "\123\357", probe_ext4
},
1112 { "ext3", 1, 0x38, 2, "\123\357", probe_ext3
},
1113 { "ext2", 1, 0x38, 2, "\123\357", probe_ext2
},
1114 { "reiserfs", 8, 0x34, 8, "ReIsErFs", probe_reiserfs
},
1115 { "reiserfs", 64, 0x34, 9, "ReIsEr2Fs", probe_reiserfs
},
1116 { "reiserfs", 64, 0x34, 9, "ReIsEr3Fs", probe_reiserfs
},
1117 { "reiserfs", 64, 0x34, 8, "ReIsErFs", probe_reiserfs
},
1118 { "reiserfs", 8, 20, 8, "ReIsErFs", probe_reiserfs
},
1119 { "reiser4", 64, 0, 7, "ReIsEr4", probe_reiserfs4
},
1120 { "gfs2", 64, 0, 4, "\x01\x16\x19\x70", probe_gfs2
},
1121 { "gfs", 64, 0, 4, "\x01\x16\x19\x70", probe_gfs
},
1122 { "vfat", 0, 0x52, 5, "MSWIN", probe_fat
},
1123 { "vfat", 0, 0x52, 8, "FAT32 ", probe_fat
},
1124 { "vfat", 0, 0x36, 5, "MSDOS", probe_fat
},
1125 { "vfat", 0, 0x36, 8, "FAT16 ", probe_fat
},
1126 { "vfat", 0, 0x36, 8, "FAT12 ", probe_fat
},
1127 { "vfat", 0, 0, 1, "\353", probe_fat_nomagic
},
1128 { "vfat", 0, 0, 1, "\351", probe_fat_nomagic
},
1129 { "vfat", 0, 0x1fe, 2, "\125\252", probe_fat_nomagic
},
1130 { "minix", 1, 0x10, 2, "\177\023", 0 },
1131 { "minix", 1, 0x10, 2, "\217\023", 0 },
1132 { "minix", 1, 0x10, 2, "\150\044", 0 },
1133 { "minix", 1, 0x10, 2, "\170\044", 0 },
1134 { "vxfs", 1, 0, 4, "\365\374\001\245", 0 },
1135 { "xfs", 0, 0, 4, "XFSB", probe_xfs
},
1136 { "romfs", 0, 0, 8, "-rom1fs-", probe_romfs
},
1137 { "bfs", 0, 0, 4, "\316\372\173\033", 0 },
1138 { "cramfs", 0, 0, 4, "E=\315\050", probe_cramfs
},
1139 { "qnx4", 0, 4, 6, "QNX4FS", 0 },
1140 { "udf", 32, 1, 5, "BEA01", probe_udf
},
1141 { "udf", 32, 1, 5, "BOOT2", probe_udf
},
1142 { "udf", 32, 1, 5, "CD001", probe_udf
},
1143 { "udf", 32, 1, 5, "CDW02", probe_udf
},
1144 { "udf", 32, 1, 5, "NSR02", probe_udf
},
1145 { "udf", 32, 1, 5, "NSR03", probe_udf
},
1146 { "udf", 32, 1, 5, "TEA01", probe_udf
},
1147 { "iso9660", 32, 1, 5, "CD001", probe_iso9660
},
1148 { "iso9660", 32, 9, 5, "CDROM", probe_iso9660
},
1149 { "jfs", 32, 0, 4, "JFS1", probe_jfs
},
1150 { "hfsplus", 1, 0, 2, "BD", probe_hfsplus
},
1151 { "hfsplus", 1, 0, 2, "H+", 0 },
1152 { "hfs", 1, 0, 2, "BD", 0 },
1153 { "ufs", 8, 0x55c, 4, "T\031\001\000", 0 },
1154 { "hpfs", 8, 0, 4, "I\350\225\371", 0 },
1155 { "sysv", 0, 0x3f8, 4, "\020~\030\375", 0 },
1156 { "swap", 0, 0xff6, 10, "SWAP-SPACE", probe_swap0
},
1157 { "swap", 0, 0xff6, 10, "SWAPSPACE2", probe_swap1
},
1158 { "swsuspend", 0, 0xff6, 9, "S1SUSPEND", probe_swap1
},
1159 { "swsuspend", 0, 0xff6, 9, "S2SUSPEND", probe_swap1
},
1160 { "swap", 0, 0x1ff6, 10, "SWAP-SPACE", probe_swap0
},
1161 { "swap", 0, 0x1ff6, 10, "SWAPSPACE2", probe_swap1
},
1162 { "swsuspend", 0, 0x1ff6, 9, "S1SUSPEND", probe_swap1
},
1163 { "swsuspend", 0, 0x1ff6, 9, "S2SUSPEND", probe_swap1
},
1164 { "swap", 0, 0x3ff6, 10, "SWAP-SPACE", probe_swap0
},
1165 { "swap", 0, 0x3ff6, 10, "SWAPSPACE2", probe_swap1
},
1166 { "swsuspend", 0, 0x3ff6, 9, "S1SUSPEND", probe_swap1
},
1167 { "swsuspend", 0, 0x3ff6, 9, "S2SUSPEND", probe_swap1
},
1168 { "swap", 0, 0x7ff6, 10, "SWAP-SPACE", probe_swap0
},
1169 { "swap", 0, 0x7ff6, 10, "SWAPSPACE2", probe_swap1
},
1170 { "swsuspend", 0, 0x7ff6, 9, "S1SUSPEND", probe_swap1
},
1171 { "swsuspend", 0, 0x7ff6, 9, "S2SUSPEND", probe_swap1
},
1172 { "swap", 0, 0xfff6, 10, "SWAP-SPACE", probe_swap0
},
1173 { "swap", 0, 0xfff6, 10, "SWAPSPACE2", probe_swap1
},
1174 { "swsuspend", 0, 0xfff6, 9, "S1SUSPEND", probe_swap1
},
1175 { "swsuspend", 0, 0xfff6, 9, "S2SUSPEND", probe_swap1
},
1176 { "ocfs", 0, 8, 9, "OracleCFS", probe_ocfs
},
1177 { "ocfs2", 1, 0, 6, "OCFSV2", probe_ocfs2
},
1178 { "ocfs2", 2, 0, 6, "OCFSV2", probe_ocfs2
},
1179 { "ocfs2", 4, 0, 6, "OCFSV2", probe_ocfs2
},
1180 { "ocfs2", 8, 0, 6, "OCFSV2", probe_ocfs2
},
1181 { "crypt_LUKS", 0, 0, 6, "LUKS\xba\xbe", probe_luks
},
1182 { "squashfs", 0, 0, 4, "sqsh", 0 },
1183 { "squashfs", 0, 0, 4, "hsqs", 0 },
1184 { "lvm2pv", 0, 0x218, 8, "LVM2 001", probe_lvm2
},
1185 { "lvm2pv", 0, 0x018, 8, "LVM2 001", probe_lvm2
},
1186 { "lvm2pv", 1, 0x018, 8, "LVM2 001", probe_lvm2
},
1187 { "lvm2pv", 1, 0x218, 8, "LVM2 001", probe_lvm2
},
1188 { NULL
, 0, 0, 0, NULL
, NULL
}
1192 * Verify that the data in dev is consistent with what is on the actual
1193 * block device (using the devname field only). Normally this will be
1194 * called when finding items in the cache, but for long running processes
1195 * is also desirable to revalidate an item before use.
1197 * If we are unable to revalidate the data, we return the old data and
1198 * do not set the BLKID_BID_FL_VERIFIED flag on it.
1200 blkid_dev
blkid_verify(blkid_cache cache
, blkid_dev dev
)
1202 struct blkid_magic
*id
;
1203 struct blkid_probe probe
;
1204 blkid_tag_iterate iter
;
1206 const char *type
, *value
;
1215 diff
= now
- dev
->bid_time
;
1217 if ((now
> dev
->bid_time
) && (diff
> 0) &&
1218 ((diff
< BLKID_PROBE_MIN
) ||
1219 (dev
->bid_flags
& BLKID_BID_FL_VERIFIED
&&
1220 diff
< BLKID_PROBE_INTERVAL
)))
1224 printf("need to revalidate %s (time since last check %llu)\n",
1225 dev
->bid_name
, (unsigned long long)diff
));
1227 if (((probe
.fd
= open(dev
->bid_name
, O_RDONLY
)) < 0) ||
1228 (fstat(probe
.fd
, &st
) < 0)) {
1229 if (probe
.fd
>= 0) close(probe
.fd
);
1230 if (errno
!= EPERM
) {
1231 blkid_free_dev(dev
);
1234 /* We don't have read permission, just return cache data. */
1236 printf("returning unverified data for %s\n",
1241 probe
.cache
= cache
;
1248 * Iterate over the type array. If we already know the type,
1249 * then try that first. If it doesn't work, then blow away
1250 * the type information, and try again.
1255 if (!dev
->bid_type
|| !strcmp(dev
->bid_type
, "mdraid")) {
1258 if (check_mdraid(probe
.fd
, uuid
) == 0) {
1259 set_uuid(dev
, uuid
, 0);
1264 for (id
= type_array
; id
->bim_type
; id
++) {
1265 if (dev
->bid_type
&&
1266 strcmp(id
->bim_type
, dev
->bid_type
))
1269 idx
= id
->bim_kboff
+ (id
->bim_sboff
>> 10);
1270 buf
= get_buffer(&probe
, idx
<< 10, 1024);
1274 if (memcmp(id
->bim_magic
, buf
+ (id
->bim_sboff
&0x3ff),
1278 if ((id
->bim_probe
== NULL
) ||
1279 (id
->bim_probe(&probe
, id
, buf
) == 0)) {
1280 type
= id
->bim_type
;
1285 if (!id
->bim_type
&& dev
->bid_type
) {
1287 * Zap the device filesystem information and try again
1290 printf("previous fs type %s not valid, "
1291 "trying full probe\n", dev
->bid_type
));
1292 iter
= blkid_tag_iterate_begin(dev
);
1293 while (blkid_tag_next(iter
, &type
, &value
) == 0)
1294 blkid_set_tag(dev
, type
, 0, 0);
1295 blkid_tag_iterate_end(iter
);
1299 if (!dev
->bid_type
) {
1300 blkid_free_dev(dev
);
1307 dev
->bid_devno
= st
.st_rdev
;
1308 dev
->bid_time
= time(0);
1309 dev
->bid_flags
|= BLKID_BID_FL_VERIFIED
;
1310 cache
->bic_flags
|= BLKID_BIC_FL_CHANGED
;
1312 blkid_set_tag(dev
, "TYPE", type
, 0);
1314 DBG(DEBUG_PROBE
, printf("%s: devno 0x%04llx, type %s\n",
1315 dev
->bid_name
, (long long)st
.st_rdev
, type
));
1328 int blkid_known_fstype(const char *fstype
)
1330 struct blkid_magic
*id
;
1332 for (id
= type_array
; id
->bim_type
; id
++) {
1333 if (strcmp(fstype
, id
->bim_type
) == 0)
1340 int main(int argc
, char **argv
)
1347 fprintf(stderr
, "Usage: %s device\n"
1348 "Probe a single device to determine type\n", argv
[0]);
1351 if ((ret
= blkid_get_cache(&cache
, "/dev/null")) != 0) {
1352 fprintf(stderr
, "%s: error creating cache (%d)\n",
1356 dev
= blkid_get_dev(cache
, argv
[1], BLKID_DEV_NORMAL
);
1358 printf("%s: %s has an unsupported type\n", argv
[0], argv
[1]);
1361 printf("TYPE='%s'\n", dev
->bid_type
? dev
->bid_type
: "(null)");
1363 printf("LABEL='%s'\n", dev
->bid_label
);
1365 printf("UUID='%s'\n", dev
->bid_uuid
);
1367 blkid_free_dev(dev
);