diff options
Diffstat (limited to 'lib/blkid/probe.c')
-rw-r--r-- | lib/blkid/probe.c | 818 |
1 files changed, 230 insertions, 588 deletions
diff --git a/lib/blkid/probe.c b/lib/blkid/probe.c index 9969a97c..eeb544c6 100644 --- a/lib/blkid/probe.c +++ b/lib/blkid/probe.c @@ -3,7 +3,7 @@ * struct with the details * * Copyright (C) 1999 by Andries Brouwer - * Copyright (C) 1999, 2000 by Theodore Ts'o + * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o * Copyright (C) 2001 by Andreas Dilger * * %Begin-Header% @@ -39,242 +39,149 @@ #endif /* - * Do the required things for instantiating a new device. This is called if - * there is nor a probe handler for a filesystem type, and is also called by - * the filesystem-specific types to do common initialization tasks. - * - * The devname, dev_p, and id fields are required. The buf is - * a buffer to return superblock data in. + * This is a special case code to check for an MDRAID device. We do + * this special since it requires checking for a superblock at the end + * of the device. */ -static int probe_default(int fd, blkid_dev *dev_p, const char *devname, - struct blkid_magic *id, unsigned char *buf, - blkid_loff_t size) +static int check_mdraid(int fd, unsigned char *ret_uuid) { - blkid_loff_t offset; - blkid_dev dev; - struct stat st; - int ret; - - if (!devname || !dev_p || !id || !buf || fd < 0) + struct mdp_superblock_s *md; + blkid_loff_t offset; + char buf[4096]; + + if (fd < 0) return -BLKID_ERR_PARAM; - if (fstat(fd, &st) < 0 || !S_ISBLK(st.st_mode)) - return -BLKID_ERR_DEV; - - offset = (blkid_loff_t)id->bim_kboff << 10; - if (id->bim_kboff < 0) - offset += (size & ~((blkid_loff_t)(id->bim_align - 1))); + offset = (blkid_get_dev_size(fd) & ~((blkid_loff_t)65535)) - 65536; if (blkid_llseek(fd, offset, 0) < 0 || - read(fd, buf, id->bim_kbsize << 10) != id->bim_kbsize << 10) + read(fd, buf, 4096) != 4096) return -BLKID_ERR_IO; - /* Revalidate magic for blkid_validate_devname */ - if (memcmp(id->bim_magic, buf + id->bim_sboff, id->bim_len)) + /* Check for magic number */ + if (memcmp("\251+N\374", buf, 4)) return -BLKID_ERR_PARAM; - dev = blkid_new_dev(); - if (!dev) - return -BLKID_ERR_MEM; + if (!ret_uuid) + return 0; + *ret_uuid = 0; - dev->bid_name = string_copy(devname); - if (!dev->bid_name) { - ret = -BLKID_ERR_MEM; - goto exit_dev; + /* The MD UUID is not contiguous in the superblock, make it so */ + md = (struct mdp_superblock_s *)buf; + if (md->set_uuid0 || md->set_uuid1 || md->set_uuid2 || md->set_uuid3) { + memcpy(ret_uuid, &md->set_uuid0, 4); + memcpy(ret_uuid, &md->set_uuid1, 12); } + return 0; +} - /* Don't set this until there is no chance of error */ - *dev_p = dev; - dev->bid_devno = st.st_rdev; - dev->bid_devsize = size; - dev->bid_time = time(0); - dev->bid_flags |= BLKID_BID_FL_VERIFIED; - - if (id->bim_type) - blkid_create_tag(dev, "TYPE", id->bim_type, - strlen(id->bim_type)); - - DBG(printf("%s: devno 0x%04Lx, type %s\n", devname, - st.st_rdev, id->bim_type)); +static void set_uuid(blkid_dev dev, uuid_t uuid) +{ + char str[37]; - return 0; -exit_dev: - blkid_free_dev(dev); - return ret; + if (!uuid_is_null(uuid)) { + uuid_unparse(uuid, str); + blkid_set_tag(dev, "UUID", str, sizeof(str), 1); + } } -static int probe_ext2(int fd, blkid_dev *dev_p, const char *devname, +static int probe_ext2(int fd, blkid_cache cache, blkid_dev dev, struct blkid_magic *id, unsigned char *buf, - blkid_loff_t size) + const char **ret_sectype) { - blkid_dev dev; struct ext2_super_block *es; - int ret; - - if ((ret = probe_default(fd, &dev, devname, id, buf, size)) < 0) - return ret; es = (struct ext2_super_block *)buf; - DBG(printf("size = %Ld, ext2_sb.compat = %08X:%08X:%08X\n", size, + DBG(printf("ext2_sb.compat = %08X:%08X:%08X\n", blkid_le32(es->s_feature_compat), blkid_le32(es->s_feature_incompat), blkid_le32(es->s_feature_ro_compat))); /* Make sure we don't keep re-probing as ext2 for a journaled fs */ if (!strcmp(id->bim_type, "ext2") && - (blkid_le32(es->s_feature_compat) & - EXT3_FEATURE_COMPAT_HAS_JOURNAL || - blkid_le32(es->s_feature_incompat) & - EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { - blkid_free_dev(dev); + ((blkid_le32(es->s_feature_compat) & + EXT3_FEATURE_COMPAT_HAS_JOURNAL) || + (blkid_le32(es->s_feature_incompat) & + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV))) return -BLKID_ERR_PARAM; - } - - /* Don't set this until there is no chance of error */ - *dev_p = dev; - dev->bid_size = (blkid_loff_t)blkid_le32(es->s_blocks_count) << - (blkid_le32(es->s_log_block_size) + 10); + if (strlen(es->s_volume_name)) + blkid_set_tag(dev, "LABEL", es->s_volume_name, + sizeof(es->s_volume_name), 1); - if (strlen(es->s_volume_name)) { - blkid_create_tag(dev, "LABEL", es->s_volume_name, - sizeof(es->s_volume_name)); - } - - if (!uuid_is_null(es->s_uuid)) { - char uuid[37]; - uuid_unparse(es->s_uuid, uuid); - blkid_create_tag(dev, "UUID", uuid, sizeof(uuid)); - } + set_uuid(dev, es->s_uuid); return 0; } -static int probe_jbd(int fd, blkid_dev *dev_p, const char *devname, +static int probe_jbd(int fd, blkid_cache cache, blkid_dev dev, struct blkid_magic *id, unsigned char *buf, - blkid_loff_t size) + const char **ret_sectype) { - blkid_dev dev; - struct ext2_super_block *es; - int ret; - - if ((ret = probe_ext2(fd, &dev, devname, id, buf, size)) < 0) - return ret; - - es = (struct ext2_super_block *)buf; + struct ext2_super_block *es = (struct ext2_super_block *) buf; if (!(blkid_le32(es->s_feature_incompat) & - EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { - blkid_free_dev(dev); + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) return -BLKID_ERR_PARAM; - } - /* Don't set this until there is no chance of error */ - *dev_p = dev; - return 0; + return (probe_ext2(fd, cache, dev, id, buf, ret_sectype)); } -static int probe_ext3(int fd, blkid_dev *dev_p, const char *devname, - struct blkid_magic *id, unsigned char *buf, - blkid_loff_t size) +static int probe_ext3(int fd, blkid_cache cache, blkid_dev dev, + struct blkid_magic *id, unsigned char *buf, + const char **ret_sectype) { - blkid_dev dev; - struct ext2_super_block *es; + struct ext2_super_block *es = (struct ext2_super_block *) buf; int ret; - if ((ret = probe_ext2(fd, &dev, devname, id, buf, size)) < 0) - return ret; - - es = (struct ext2_super_block *)buf; - if (!(blkid_le32(es->s_feature_compat) & - EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { - blkid_free_dev(dev); - *dev_p = NULL; + EXT3_FEATURE_COMPAT_HAS_JOURNAL)) return -BLKID_ERR_PARAM; - } - /* Don't set this until there is no chance of error */ - *dev_p = dev; + + if ((ret = probe_ext2(fd, cache, dev, id, buf, ret_sectype)) < 0) + return ret; if (!(blkid_le32(es->s_feature_incompat) & - EXT3_FEATURE_INCOMPAT_RECOVER)) { - blkid_create_tag(dev, "TYPE", "ext2", 4); - dev->bid_flags |= BLKID_BID_FL_MTYPE; - } + EXT3_FEATURE_INCOMPAT_RECOVER)) + *ret_sectype = "ext2"; return 0; } -static int probe_vfat(int fd, blkid_dev *dev_p, const char *devname, +static int probe_vfat(int fd, blkid_cache cache, blkid_dev dev, struct blkid_magic *id, unsigned char *buf, - blkid_loff_t size) + const char **ret_sectype) { - blkid_dev dev; struct vfat_super_block *vs; char serno[10]; - blkid_loff_t sectors; - int cluster_size; - int ret; - - if ((ret = probe_default(fd, &dev, devname, id, buf, size)) < 0) - return ret; vs = (struct vfat_super_block *)buf; - /* Don't set this until there is no chance of error */ - *dev_p = dev; - - sectors = ((vs->vs_sectors[1] << 8) | vs->vs_sectors[0]); - if (sectors == 0) - sectors = vs->vs_total_sect; - cluster_size = ((vs->vs_sector_size[1] << 8) | vs->vs_sector_size[0]); - dev->bid_size = sectors * cluster_size; - DBG(printf("%lld %d byte sectors\n", sectors, cluster_size)); - if (strncmp(vs->vs_label, "NO NAME", 7)) { char *end = vs->vs_label + sizeof(vs->vs_label) - 1; while (*end == ' ' && end >= vs->vs_label) --end; if (end >= vs->vs_label) - blkid_create_tag(dev, "LABEL", vs->vs_label, - end - vs->vs_label + 1); + blkid_set_tag(dev, "LABEL", vs->vs_label, + end - vs->vs_label + 1, 1); } /* We can't just print them as %04X, because they are unaligned */ sprintf(serno, "%02X%02X-%02X%02X", vs->vs_serno[3], vs->vs_serno[2], vs->vs_serno[1], vs->vs_serno[0]); - blkid_create_tag(dev, "UUID", serno, sizeof(serno)); + blkid_set_tag(dev, "UUID", serno, sizeof(serno), 1); return 0; } -static int probe_msdos(int fd, blkid_dev *dev_p, const char *devname, +static int probe_msdos(int fd, blkid_cache cache, blkid_dev dev, struct blkid_magic *id, unsigned char *buf, - blkid_loff_t size) + const char **ret_sectype) { - blkid_dev dev; - struct msdos_super_block *ms; + struct msdos_super_block *ms = (struct msdos_super_block *) buf; char serno[10]; - int cluster_size; - blkid_loff_t sectors; - int ret; - - if ((ret = probe_default(fd, &dev, devname, id, buf, size)) < 0) - return ret; - - ms = (struct msdos_super_block *)buf; - - /* Don't set this until there is no chance of error */ - *dev_p = dev; - - sectors = ((ms->ms_sectors[1] << 8) | ms->ms_sectors[0]); - if (sectors == 0) - sectors = ms->ms_total_sect; - cluster_size = ((ms->ms_sector_size[1] << 8) | ms->ms_sector_size[0]); - dev->bid_size = sectors * cluster_size; - DBG(printf("%Ld %d byte sectors\n", sectors, cluster_size)); if (strncmp(ms->ms_label, "NO NAME", 7)) { char *end = ms->ms_label + sizeof(ms->ms_label) - 1; @@ -282,445 +189,133 @@ static int probe_msdos(int fd, blkid_dev *dev_p, const char *devname, while (*end == ' ' && end >= ms->ms_label) --end; if (end >= ms->ms_label) - blkid_create_tag(dev, "LABEL", ms->ms_label, - end - ms->ms_label + 1); + blkid_set_tag(dev, "LABEL", ms->ms_label, + end - ms->ms_label + 1, 1); } /* We can't just print them as %04X, because they are unaligned */ sprintf(serno, "%02X%02X-%02X%02X", ms->ms_serno[3], ms->ms_serno[2], ms->ms_serno[1], ms->ms_serno[0]); - blkid_create_tag(dev, "UUID", serno, sizeof(serno)); + blkid_set_tag(dev, "UUID", serno, 0, 1); return 0; } -static int probe_xfs(int fd, blkid_dev *dev_p, const char *devname, +static int probe_xfs(int fd, blkid_cache cache, blkid_dev dev, struct blkid_magic *id, unsigned char *buf, - blkid_loff_t size) + const char **ret_sectype) { - blkid_dev dev; struct xfs_super_block *xs; - int ret; - - if ((ret = probe_default(fd, &dev, devname, id, buf, size)) < 0) - return ret; xs = (struct xfs_super_block *)buf; - /* Don't set this until there is no chance of error */ - *dev_p = dev; - /* If the filesystem size is larger than the device, this is bad */ - dev->bid_size = blkid_be64(xs->xs_dblocks) * - blkid_be32(xs->xs_blocksize); - if (strlen(xs->xs_fname)) - blkid_create_tag(dev, "LABEL", xs->xs_fname, - sizeof(xs->xs_fname)); - - if (!uuid_is_null(xs->xs_uuid)) { - char uuid[37]; - uuid_unparse(xs->xs_uuid, uuid); - blkid_create_tag(dev, "UUID", uuid, sizeof(uuid)); - } + blkid_set_tag(dev, "LABEL", xs->xs_fname, + sizeof(xs->xs_fname), 1); + set_uuid(dev, xs->xs_uuid); return 0; } -static int probe_reiserfs(int fd, blkid_dev *dev_p, const char *devname, +static int probe_reiserfs(int fd, blkid_cache cache, blkid_dev dev, struct blkid_magic *id, unsigned char *buf, - blkid_loff_t size) + const char **ret_sectype) { - blkid_dev dev; - struct reiserfs_super_block *rs; + struct reiserfs_super_block *rs = (struct reiserfs_super_block *) buf; unsigned int blocksize; - int ret; - - if ((ret = probe_default(fd, &dev, devname, id, buf, size)) < 0) - return ret; - - rs = (struct reiserfs_super_block *)buf; blocksize = blkid_le16(rs->rs_blocksize); /* If the superblock is inside the journal, we have the wrong one */ - if (id->bim_kboff/(blocksize>>10) > blkid_le32(rs->rs_journal_block)) { - blkid_free_dev(dev); + if (id->bim_kboff/(blocksize>>10) > blkid_le32(rs->rs_journal_block)) return -BLKID_ERR_BIG; - } - - /* Don't set this until there is no chance of error */ - *dev_p = dev; - - /* If the filesystem size is larger than the device, this is bad */ - dev->bid_size = blkid_le32(rs->rs_blocks_count) * blocksize; /* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */ if (!strcmp(id->bim_magic, "ReIsEr2Fs") || !strcmp(id->bim_magic, "ReIsEr3Fs")) { if (strlen(rs->rs_label)) { - blkid_create_tag(dev, "LABEL", rs->rs_label, - sizeof(rs->rs_label)); - } - - if (!uuid_is_null(rs->rs_uuid)) { - char uuid[37]; - uuid_unparse(rs->rs_uuid, uuid); - blkid_create_tag(dev, "UUID", uuid, sizeof(uuid)); + blkid_set_tag(dev, "LABEL", rs->rs_label, + sizeof(rs->rs_label), 1); } - } - - return 0; -} -static int probe_minix(int fd, blkid_dev *dev_p, const char *devname, - struct blkid_magic *id, unsigned char *buf, - blkid_loff_t size) -{ - blkid_dev dev; - struct minix_super_block *ms; - int ret; - - if ((ret = probe_default(fd, &dev, devname, id, buf, size)) < 0) - return ret; - - ms = (struct minix_super_block *)buf; - - /* Don't set this until there is no chance of error */ - *dev_p = dev; - dev->bid_size = ms->ms_nzones << ms->ms_log_zone_size; - return 0; -} - -static int probe_swap(int fd, blkid_dev *dev_p, const char *devname, - struct blkid_magic *id, unsigned char *buf, - blkid_loff_t size) -{ - blkid_dev dev; - struct swap_header *sh; - int psize; - int ret; - - if ((ret = probe_default(fd, &dev, devname, id, buf, size)) < 0) - return ret; - - /* PAGE_SIZE can be found by where the magic is located */ - psize = (id->bim_kboff << 10) + (id->bim_sboff + 10); - - /* Don't set this until there is no chance of error */ - *dev_p = dev; - - sh = (struct swap_header *)buf; - /* Is swap data in local endian format? */ - dev->bid_size = (blkid_loff_t)(sh->sh_last_page + 1) * psize; - - /* A label can not exist on the old (128MB max) swap format */ - if (!strcmp(id->bim_magic, "SWAPSPACE2") && sh->sh_label[0]) { - blkid_create_tag(dev, "LABEL", sh->sh_label, - sizeof(sh->sh_label)); + set_uuid(dev, rs->rs_uuid); } return 0; } -static int probe_mdraid(int fd, blkid_dev *dev_p, const char *devname, - struct blkid_magic *id, unsigned char *buf, - blkid_loff_t size) -{ - blkid_dev dev; - struct mdp_superblock_s *md; - int ret; - - if ((ret = probe_default(fd, &dev, devname, id, buf, size)) < 0) - return ret; - - /* Don't set this until there is no chance of error */ - *dev_p = dev; - - md = (struct mdp_superblock_s *)buf; - /* What units is md->size in? Assume 512-byte sectors? */ - dev->bid_size = md->size * 512; - - /* The MD UUID is not contiguous in the superblock, make it so */ - if (md->set_uuid0 || md->set_uuid1 || md->set_uuid2 || md->set_uuid3) { - unsigned char md_uuid[16]; - char uuid[37]; - - memcpy(md_uuid, &md->set_uuid0, 4); - memcpy(md_uuid + 4, &md->set_uuid1, 12); - - uuid_unparse(md_uuid, uuid); - blkid_create_tag(dev, "UUID", uuid, sizeof(uuid)); - } - return 0; -} - -static int probe_hfs(int fd, blkid_dev *dev_p, const char *devname, - struct blkid_magic *id, unsigned char *buf, - blkid_loff_t size) -{ - blkid_dev dev; - struct hfs_super_block *hfs; - int ret; - - if ((ret = probe_default(fd, &dev, devname, id, buf, size)) < 0) - return ret; - - hfs = (struct hfs_super_block *)buf; - - if (blkid_be32(hfs->h_blksize) != 512) - return -BLKID_ERR_PARAM; - - /* Don't set this until there is no chance of error */ - *dev_p = dev; - - return 0; -} - - /* * BLKID_BLK_OFFS is at least as large as the highest bim_kboff defined - * in the type_array table below + bim_kbalign. If we ever start looking for magics - * relative to the end of a device, we can start using negative offsets - * in type_array. + * in the type_array table below + bim_kbalign. + * + * When probing for a lot of magics, we handle everything in 1kB buffers so + * that we don't have to worry about reading each combination of block sizes. */ -#define BLKID_BLK_BITS (10) -#define BLKID_BLK_KBITS (BLKID_BLK_BITS - 10) -#define BLKID_BLK_SIZE (1024 << BLKID_BLK_KBITS) -#define BLKID_BLK_MASK (BLKID_BLK_SIZE - 1) -#define BLKID_BLK_OFFS 128 /* currently MDRAID kboff + align */ +#define BLKID_BLK_OFFS 64 /* currently reiserfs */ /* * Various filesystem magics that we can check for. Note that kboff and * sboff are in kilobytes and bytes respectively. All magics are in * byte strings so we don't worry about endian issues. */ -struct blkid_magic type_array[] = { -/* type kboff sboff len magic align kbsize probe */ - { "MDRAID", -64, 0, 4, "\251+N\374", 65536, 4, probe_mdraid }, -/*{ "LVM", 0, 0, 4, "HM\001\000", 1, 4, probe_lvm },*/ - { "jbd", 1, 0x38, 2, "\123\357", 1, 1, probe_jbd }, - { "ext3", 1, 0x38, 2, "\123\357", 1, 1, probe_ext3 }, - { "ext2", 1, 0x38, 2, "\123\357", 1, 1, probe_ext2 }, - { "reiserfs", 8, 0x34, 8, "ReIsErFs", 1, 1, probe_reiserfs }, - { "reiserfs", 64, 0x34, 9, "ReIsEr2Fs", 1, 1, probe_reiserfs }, - { "reiserfs", 64, 0x34, 9, "ReIsEr3Fs", 1, 1, probe_reiserfs }, - { "reiserfs", 64, 0x34, 8, "ReIsErFs", 1, 1, probe_reiserfs }, - { "reiserfs", 8, 20, 8, "ReIsErFs", 1, 1, probe_reiserfs }, - { "ntfs", 0, 3, 8, "NTFS ", 1, 1, probe_default }, - { "vfat", 0, 0x52, 5, "MSWIN", 1, 1, probe_vfat }, - { "vfat", 0, 0x52, 8, "FAT32 ", 1, 1, probe_vfat }, - { "msdos", 0, 0x36, 5, "MSDOS", 1, 1, probe_msdos }, - { "msdos", 0, 0x36, 8, "FAT16 ", 1, 1, probe_msdos }, - { "msdos", 0, 0x36, 8, "FAT12 ", 1, 1, probe_msdos }, - { "minix", 1, 0x10, 2, "\177\023", 1, 1, probe_minix }, - { "minix", 1, 0x10, 2, "\217\023", 1, 1, probe_minix }, - { "minix", 1, 0x10, 2, "\150\044", 1, 1, probe_minix }, - { "minix", 1, 0x10, 2, "\170\044", 1, 1, probe_minix }, - { "vxfs", 1, 0, 4, "\365\374\001\245", 1, 1, probe_default }, - { "xfs", 0, 0, 4, "XFSB", 1, 1, probe_xfs }, - { "romfs", 0, 0, 8, "-rom1fs-", 1, 1, probe_default }, - { "bfs", 0, 0, 4, "\316\372\173\033", 1, 1, probe_default }, - { "cramfs", 0, 0, 4, "E=\315\034", 1, 1, probe_default }, - { "qnx4", 0, 4, 6, "QNX4FS", 1, 1, probe_default }, - { "iso9660", 32, 1, 5, "CD001", 1, 1, probe_default }, - { "iso9660", 32, 9, 5, "CDROM", 1, 1, probe_default }, - { "udf", 32, 1, 5, "BEA01", 1, 1, probe_default }, - { "udf", 32, 1, 5, "BOOT2", 1, 1, probe_default }, - { "udf", 32, 1, 5, "CD001", 1, 1, probe_default }, - { "udf", 32, 1, 5, "CDW02", 1, 1, probe_default }, - { "udf", 32, 1, 5, "NSR02", 1, 1, probe_default }, - { "udf", 32, 1, 5, "NSR03", 1, 1, probe_default }, - { "udf", 32, 1, 5, "TEA01", 1, 1, probe_default }, - { "jfs", 32, 0, 4, "JFS1", 1, 1, probe_default }, - { "hfs", 1, 0, 2, "BD", 1, 1, probe_hfs }, - { "ufs", 8, 0x55c, 4, "T\031\001\000", 1, 1, probe_default }, - { "hpfs", 8, 0, 4, "I\350\225\371", 1, 1, probe_default }, - { "sysv", 0, 0x3f8, 4, "\020~\030\375", 1, 1, probe_default }, - { "swap", 0, 0xff6, 10, "SWAP-SPACE", 1, 4, probe_swap }, - { "swap", 0, 0xff6, 10, "SWAPSPACE2", 1, 4, probe_swap }, - { "swap", 0, 0x1ff6, 10, "SWAP-SPACE", 1, 8, probe_swap }, - { "swap", 0, 0x1ff6, 10, "SWAPSPACE2", 1, 8, probe_swap }, - { "swap", 0, 0x3ff6, 10, "SWAP-SPACE", 1, 16, probe_swap }, - { "swap", 0, 0x3ff6, 10, "SWAPSPACE2", 1, 16, probe_swap }, - { NULL, 0, 0, 0, NULL, 1, 0, NULL } +static struct blkid_magic type_array[] = { +/* type kboff sboff len magic probe */ + { "jbd", 1, 0x38, 2, "\123\357", probe_jbd }, + { "ext3", 1, 0x38, 2, "\123\357", probe_ext3 }, + { "ext2", 1, 0x38, 2, "\123\357", probe_ext2 }, + { "reiserfs", 8, 0x34, 8, "ReIsErFs", probe_reiserfs }, + { "reiserfs", 64, 0x34, 9, "ReIsEr2Fs", probe_reiserfs }, + { "reiserfs", 64, 0x34, 9, "ReIsEr3Fs", probe_reiserfs }, + { "reiserfs", 64, 0x34, 8, "ReIsErFs", probe_reiserfs }, + { "reiserfs", 8, 20, 8, "ReIsErFs", probe_reiserfs }, + { "ntfs", 0, 3, 8, "NTFS ", 0 }, + { "vfat", 0, 0x52, 5, "MSWIN", probe_vfat }, + { "vfat", 0, 0x52, 8, "FAT32 ", probe_vfat }, + { "msdos", 0, 0x36, 5, "MSDOS", probe_msdos }, + { "msdos", 0, 0x36, 8, "FAT16 ", probe_msdos }, + { "msdos", 0, 0x36, 8, "FAT12 ", probe_msdos }, + { "minix", 1, 0x10, 2, "\177\023", 0 }, + { "minix", 1, 0x10, 2, "\217\023", 0 }, + { "minix", 1, 0x10, 2, "\150\044", 0 }, + { "minix", 1, 0x10, 2, "\170\044", 0 }, + { "vxfs", 1, 0, 4, "\365\374\001\245", 0 }, + { "xfs", 0, 0, 4, "XFSB", probe_xfs }, + { "romfs", 0, 0, 8, "-rom1fs-", 0 }, + { "bfs", 0, 0, 4, "\316\372\173\033", 0 }, + { "cramfs", 0, 0, 4, "E=\315\034", 0 }, + { "qnx4", 0, 4, 6, "QNX4FS", 0 }, + { "iso9660", 32, 1, 5, "CD001", 0 }, + { "iso9660", 32, 9, 5, "CDROM", 0 }, + { "udf", 32, 1, 5, "BEA01", 0 }, + { "udf", 32, 1, 5, "BOOT2", 0 }, + { "udf", 32, 1, 5, "CD001", 0 }, + { "udf", 32, 1, 5, "CDW02", 0 }, + { "udf", 32, 1, 5, "NSR02", 0 }, + { "udf", 32, 1, 5, "NSR03", 0 }, + { "udf", 32, 1, 5, "TEA01", 0 }, + { "jfs", 32, 0, 4, "JFS1", 0 }, + { "hfs", 1, 0, 2, "BD", 0 }, + { "ufs", 8, 0x55c, 4, "T\031\001\000", 0 }, + { "hpfs", 8, 0, 4, "I\350\225\371", 0 }, + { "sysv", 0, 0x3f8, 4, "\020~\030\375", 0 }, + { "swap", 0, 0xff6, 10, "SWAP-SPACE", 0 }, + { "swap", 0, 0xff6, 10, "SWAPSPACE2", 0 }, + { "swap", 0, 0x1ff6, 10, "SWAP-SPACE", 0 }, + { "swap", 0, 0x1ff6, 10, "SWAPSPACE2", 0 }, + { "swap", 0, 0x3ff6, 10, "SWAP-SPACE", 0 }, + { "swap", 0, 0x3ff6, 10, "SWAPSPACE2", 0 }, + { NULL, 0, 0, 0, NULL, NULL } }; - -/* - * When probing for a lot of magics, we handle everything in 1kB buffers so - * that we don't have to worry about reading each combination of block sizes. - */ -static unsigned char *read_one_buf(int fd, blkid_loff_t offset) -{ - unsigned char *buf; - - if (lseek(fd, offset, SEEK_SET) < 0) - return NULL; - - if (!(buf = (unsigned char *)malloc(BLKID_BLK_SIZE))) - return NULL; - - if (read(fd, buf, BLKID_BLK_SIZE) != BLKID_BLK_SIZE) { - free(buf); - return NULL; - } - - return buf; -} - -static unsigned char *read_sb_buf(int fd, unsigned char **bufs, int kboff, - blkid_loff_t start) -{ - int idx = kboff >> BLKID_BLK_KBITS; - unsigned char **buf; - - if (idx > BLKID_BLK_OFFS || idx < -BLKID_BLK_OFFS) { - fprintf(stderr, "reading from invalid offset %d (%d)!\n", - kboff, idx); - return NULL; - } - - buf = bufs + idx; - if (!*buf) - *buf = read_one_buf(fd, start); - - return *buf; -} - -static struct blkid_magic *devname_to_magic(const char *devname, int fd, - unsigned char **bufs, - struct blkid_magic *id, - blkid_loff_t size) -{ - struct blkid_magic *ret = NULL; - - if (!bufs || fd < 0) - return NULL; - - if (id >= type_array + sizeof(type_array) / sizeof(*id)) - return NULL; - - for (id = id < type_array ? type_array : id + 1; id->bim_type; ++id) { - unsigned char *buf; - blkid_loff_t start = 0LL; - blkid_loff_t offset = 0LL; - int kboff; - - offset = ((blkid_loff_t)id->bim_kboff << 10) + - (id->bim_sboff & ~0x3ffULL); - /* - * We index negative buffers by their actual offset (including - * superblock offsets > 1kB, not the aligned offset, so that - * we correctly access negative buffers with different - * alignment requirements. - */ - if (id->bim_kboff < 0) { - start = (size & ~((blkid_loff_t)(id->bim_align - 1))) + - offset; - if (start < 0) /* Device too small for alignment */ - continue; - kboff = (start - size) >> 10; - } else { - start = offset; - kboff = offset >> 10; - } - - if ((buf = - read_sb_buf(fd, bufs, kboff, start)) && - !memcmp(id->bim_magic, buf + (id->bim_sboff&0x3ffULL), - id->bim_len)) { - ret = id; - break; - } - } - - return ret; -} - /* - * Get data from a single block special device. - * - * Return a blkid_dev with at least the device type and size set. - * If the passed-in size is zero, then we get the device size here. + * If a device's filesystem no longer checks out, we need to nuke + * information about it from the entry. */ -blkid_dev blkid_devname_to_dev(const char *devname, blkid_loff_t size) +static void blkid_invalidate_fs(blkid_dev dev) { - unsigned char *buf_array[BLKID_BLK_OFFS * 2 + 1]; - unsigned char **bufs = buf_array + BLKID_BLK_OFFS; - blkid_dev dev = NULL, last = NULL; - unsigned char *sb_buf = NULL; - int sb_size = 0; - struct blkid_magic *id = NULL; - blkid_loff_t diff_last = 0xf000000000000000ULL; - int fd; - - if (!devname) - return NULL; - - fd = open(devname, O_RDONLY); - if (fd < 0) - return NULL; - - if (!size) - size = blkid_get_dev_size(fd); - if (size < 1024) - goto exit_fd; - - memset(buf_array, 0, sizeof(buf_array)); - - while ((id = devname_to_magic(devname, fd, bufs, id, size)) && - diff_last) { - int new_sb; - blkid_loff_t diff_dev; - - DBG(printf("found type %s (#%d) on %s, probing\n", - id->bim_type, id - type_array, devname)); - - new_sb = id->bim_kbsize << 10; - if (sb_size < new_sb) { - unsigned char *sav = sb_buf; - if (!(sb_buf = realloc(sb_buf, new_sb))) { - sb_buf = sav; - continue; - } - sb_size = new_sb; - } - - if (id->bim_probe(fd, &dev, devname, id, sb_buf, size) < 0) - continue; - - diff_dev = size - dev->bid_size; - DBG(printf("size = %Lu, fs size = %Lu\n", size, dev->bid_size)); - DBG(printf("checking best match: old %Ld, new %Ld\n", - diff_last, diff_dev)); - /* See which type is a better match by checking size */ - if ((diff_last < 0 && diff_dev > diff_last) || - (diff_last > 0 && diff_dev >= 0 && diff_dev < diff_last)) { - if (last) - blkid_free_dev(last); - last = dev; - diff_last = diff_dev; - } else - blkid_free_dev(dev); - } - - if (!last) - DBG(printf("unknown device type on %s\n", devname)); - else - DBG(printf(last)); - - /* Free up any buffers we allocated */ - for (bufs = buf_array; bufs - buf_array < sizeof(buf_array) / - sizeof(buf_array[0]); bufs++) { - if (*bufs) - free(*bufs); - } - - if (sb_buf) - free(sb_buf); -exit_fd: - close(fd); - return last; -} + blkid_set_tag(dev, "TYPE", 0, 0, 0); + blkid_set_tag(dev, "LABEL", 0, 0, 0); + blkid_set_tag(dev, "UUID", 0, 0, 0); +} /* * Verify that the data in dev is consistent with what is on the actual @@ -733,13 +328,12 @@ exit_fd: */ blkid_dev blkid_verify_devname(blkid_cache cache, blkid_dev dev) { - blkid_loff_t size; struct blkid_magic *id; - blkid_dev new = NULL; - unsigned char *sb_buf = NULL; - int sb_size = 0; + unsigned char *bufs[BLKID_BLK_OFFS + 1], *buf; + const char *sec_type, *type; + struct stat st; time_t diff; - int fd; + int fd, idx; if (!dev) return NULL; @@ -752,10 +346,9 @@ blkid_dev blkid_verify_devname(blkid_cache cache, blkid_dev dev) DBG(printf("need to revalidate %s\n", dev->bid_name)); - if ((fd = open(dev->bid_name, O_RDONLY)) < 0) { + if (((fd = open(dev->bid_name, O_RDONLY)) < 0) || + (fstat(fd, &st) < 0) || !S_ISBLK(st.st_mode)) { if (errno == ENXIO || errno == ENODEV) { - fprintf(stderr, "unable to open %s for revalidation\n", - dev->bid_name); blkid_free_dev(dev); return NULL; } @@ -764,68 +357,117 @@ blkid_dev blkid_verify_devname(blkid_cache cache, blkid_dev dev) return dev; } - size = blkid_get_dev_size(fd); - - /* See if we can probe this device by its existing type directly */ + memset(bufs, 0, sizeof(bufs)); + + /* + * Iterate over the type array. If we already know the type, + * then try that first. If it doesn't work, then blow away + * the type information, and try again. + * + */ +try_again: + type = 0; + sec_type = 0; + if (!dev->bid_type || !strcmp(dev->bid_type, "mdraid")) { + uuid_t uuid; + + if (check_mdraid(fd, uuid) == 0) { + set_uuid(dev, uuid); + type = "mdraid"; + goto found_type; + } + } for (id = type_array; id->bim_type; id++) { - if (!strcmp(id->bim_type, dev->bid_type)) { - int new_sb = id->bim_kbsize << 10; - /* See if we need to allocate a larger sb buffer */ - if (sb_size < new_sb) { - unsigned char *sav = sb_buf; - - /* We can't revalidate, return old dev */ - if (!(sb_buf = realloc(sb_buf, new_sb))) { - fprintf(stderr, "not enough memory for " - "%s revalidation\n", - dev->bid_name); - free(sav); - goto exit_fd; - } - sb_size = new_sb; + if (dev->bid_type && + strcmp(id->bim_type, dev->bid_type)) + continue; + + idx = id->bim_kboff + (id->bim_sboff >> 10); + if (idx > BLKID_BLK_OFFS || idx < 0) + continue; + buf = bufs[idx]; + if (!buf) { + if (lseek(fd, idx << 10, SEEK_SET) < 0) + continue; + + if (!(buf = (unsigned char *)malloc(1024))) + continue; + + if (read(fd, buf, 1024) != 1024) { + free(buf); + continue; } + bufs[idx] = buf; + } - if (id->bim_probe(fd, &new, dev->bid_name, id, sb_buf, - size) == 0) - break; + if (memcmp(id->bim_magic, buf + (id->bim_sboff&0x3ff), + id->bim_len)) + continue; + + if ((id->bim_probe == NULL) || + (id->bim_probe(fd, cache, dev, id, buf, &sec_type) == 0)) { + type = id->bim_type; + goto found_type; } } - if (sb_buf) - free(sb_buf); + if (!id->bim_type && dev->bid_type) { + /* + * Zap the device filesystem type and try again + */ + blkid_invalidate_fs(dev); + goto try_again; + } - /* Otherwise we need to determine the device type first */ - if (new || (new = blkid_devname_to_dev(dev->bid_name, size))) { - new->bid_id = dev->bid_id; /* save old id for cache */ + if (!dev->bid_type) { blkid_free_dev(dev); - dev = blkid_add_dev_to_cache(cache, new); + return NULL; + } + +found_type: + if (dev && type) { + dev->bid_devno = st.st_rdev; + dev->bid_time = time(0); + dev->bid_flags |= BLKID_BID_FL_VERIFIED; + + blkid_set_tag(dev, "TYPE", type, 0, 1); + if (sec_type) + blkid_set_tag(dev, "TYPE", sec_type, 0, 0); + + DBG(printf("%s: devno 0x%04Lx, type %s\n", + dev->bid_name, st.st_rdev, type)); } -exit_fd: close(fd); - /* In case the cache is missing the device size */ - if (dev->bid_devsize == 0) - dev->bid_devsize = size; return dev; - } #ifdef TEST_PROGRAM int main(int argc, char **argv) { blkid_dev dev; + blkid_cache cache; if (argc != 2) { fprintf(stderr, "Usage: %s device\n" "Probe a single device to determine type\n", argv[0]); exit(1); } - dev = blkid_devname_to_dev(argv[1], 0); - if (dev) - blkid_free_dev(dev); - else + cache = blkid_new_cache(); + dev = blkid_get_devname(cache, argv[1], BLKID_DEV_NORMAL); + if (!dev) { printf("%s: %s has an unsupported type\n", argv[0], argv[1]); + return (1); + } + printf("%s is type %s\n", argv[1], dev->bid_type ? + dev->bid_type : "(null)"); + if (dev->bid_label) + printf("\tlabel is '%s'\n", dev->bid_label); + if (dev->bid_uuid) + printf("\tuuid is %s\n", dev->bid_uuid); + + blkid_free_dev(dev); return (0); } #endif |