Пример #1
0
/*
 * Get both label and uuid.
 * For now, only ext2, ext3, xfs, ocfs, ocfs2, reiserfs, swap are supported
 *
 * Return 0 on success.
 */
int
get_label_uuid(const char *device, char **label, char *uuid) {
    int fd;
    struct ext2_super_block e2sb;
    struct xfs_super_block xfsb;
    struct jfs_super_block jfssb;
    struct ocfs_volume_header ovh;	/* Oracle */
    struct ocfs_volume_label olbl;
    struct ocfs2_super_block osb;
    struct reiserfs_super_block reiserfssb;
    int blksize;
    int rv = 0;

    fd = open(device, O_RDONLY);
    if (fd < 0)
        return -1;

    /* If there is a RAID partition, or an error, ignore this partition */
    if (is_raid_partition(fd)) {
        rv = 1;
        goto done;
    }

    if (is_v1_swap_partition(fd, label, uuid))
        goto done;

    if (lseek(fd, 1024, SEEK_SET) == 1024
            && read(fd, (char *) &e2sb, sizeof(e2sb)) == sizeof(e2sb)
            && (ext2magic(e2sb) == EXT2_SUPER_MAGIC)) {
        store_uuid(uuid, e2sb.s_uuid);
        store_label(label, e2sb.s_volume_name,
                    sizeof(e2sb.s_volume_name));
        goto done;
    }

    if (lseek(fd, 0, SEEK_SET) == 0
            && read(fd, (char *) &xfsb, sizeof(xfsb)) == sizeof(xfsb)
            && (strncmp(xfsb.s_magic, XFS_SUPER_MAGIC, 4) == 0)) {
        store_uuid(uuid, xfsb.s_uuid);
        store_label(label, xfsb.s_fname, sizeof(xfsb.s_fname));
        goto done;
    }

    if (lseek(fd, 0, SEEK_SET) == 0
            && read(fd, (char *) &ovh, sizeof(ovh)) == sizeof(ovh)
            && (strncmp(ovh.signature, OCFS_MAGIC, sizeof(OCFS_MAGIC)) == 0)
            && (lseek(fd, 512, SEEK_SET) == 512)
            && read(fd, (char *) &olbl, sizeof(olbl)) == sizeof(olbl)) {
        store_uuid(uuid, NULL);
        store_label(label, olbl.label, ocfslabellen(olbl));
        goto done;
    }

    if (lseek(fd, JFS_SUPER1_OFF, SEEK_SET) == JFS_SUPER1_OFF
            && read(fd, (char *) &jfssb, sizeof(jfssb)) == sizeof(jfssb)
            && (strncmp(jfssb.s_magic, JFS_MAGIC, 4) == 0)) {

        /* The situation for jfs is rather messy. The structure of the
           superblock changed a few times, but there seems to be no good way
           to check what kind of sb we have.
           Old (OS/2 compatible) jfs filesystems don't have UUIDs and have
           an 11-byte label in s_fpack[].
           Kernel 2.5.6 supports jfs v1; 2.5.8 supports v2; 2.5.18 has label/uuid.
           Kernel 2.4.20 supports jfs v2 with label/uuid.
           s_version will be 2 for new filesystems using an external log.
           Other new filesystems will have version 1.
           Label and UUID can be set by jfs_tune. */

        /* Let us believe label/uuid on v2, and on v1 only when label agrees
           with s_fpack in the first 11 bytes. */

        if (assemble4le(jfssb.s_version) == 1 &&
                strncmp(jfssb.s_label, jfssb.s_fpack, 11) != 0) {
            store_uuid(uuid, NULL);
            store_label(label, jfssb.s_fpack,
                        sizeof(jfssb.s_fpack));
        } else {
            store_uuid(uuid, jfssb.s_uuid);
            store_label(label, jfssb.s_label,
                        sizeof(jfssb.s_label));
        }
        goto done;
    }

    if (lseek(fd, REISERFS_DISK_OFFSET_IN_BYTES, SEEK_SET)
            == REISERFS_DISK_OFFSET_IN_BYTES
            && read(fd, (char *) &reiserfssb, sizeof(reiserfssb))
            == sizeof(reiserfssb)
            /* Only 3.6.x format supers have labels or uuids.
               Label and UUID can be set by reiserfstune -l/-u. */
            && reiserfs_magic_version(reiserfssb.s_magic) > 1) {
        store_uuid(uuid, reiserfssb.s_uuid);
        store_label(label, reiserfssb.s_label,
                    sizeof(reiserfssb.s_label));
        goto done;
    }

    for (blksize = OCFS2_MIN_BLOCKSIZE;
            blksize <= OCFS2_MAX_BLOCKSIZE;
            blksize <<= 1) {
        int blkoff = blksize * OCFS2_SUPER_BLOCK_BLKNO;

        if (lseek(fd, blkoff, SEEK_SET) == blkoff
                && read(fd, (char *) &osb, sizeof(osb)) == sizeof(osb)
                && strncmp(osb.signature,
                           OCFS2_SUPER_BLOCK_SIGNATURE,
                           sizeof(OCFS2_SUPER_BLOCK_SIGNATURE)) == 0) {
            store_uuid(uuid, osb.s_uuid);
            store_label(label, osb.s_label, sizeof(osb.s_label));
            goto done;
        }
    }
    rv = 1;
done:
    close(fd);
    return rv;
}
Пример #2
0
char *fstype(const char *device)
{
    int fd;
    char *type = NULL;
    struct stat64 statbuf;

    /*
     * opening and reading an arbitrary unknown path can have
     * undesired side effects - first check that `device' refers
     * to a block device
     */
    if(
        stat64(device, &statbuf) ||
        !(S_ISBLK(statbuf.st_mode) || S_ISREG(statbuf.st_mode))
    ) {
        return 0;
    }

    fd = open(device, O_RDONLY | O_LARGEFILE);
    /* try harder */
    if(fd < 0 && errno == ENOMEDIUM) fd = open(device, O_RDONLY | O_LARGEFILE);
    if(fd < 0) {
        perror_debug((char *) device);
        return 0;
    }

    /*
     * do seeks and reads in disk order, otherwise a very short
     * partition may cause a failure because of read error
     */

    if(!type) {
        union {
            struct xiafs_super_block xiasb;
            char romfs_magic[8];
            char qnx4fs_magic[10];	/* ignore first 4 bytes */
            long bfs_magic;
            struct ntfs_super_block ntfssb;
            struct fat_super_block fatsb;
            struct xfs_super_block xfsb;
            struct cramfs_super_block cramfssb;
            unsigned char data[512];
        } xsb;

        /* block 0 */
        if(
            lseek(fd, 0, SEEK_SET) == 0 &&
            read(fd, &xsb, sizeof xsb) == sizeof xsb
        ) {
            if(xiafsmagic(xsb.xiasb) == _XIAFS_SUPER_MAGIC) {
                type = "xiafs";
            }
            else if(!strncmp(xsb.romfs_magic, "-rom1fs-", 8)) {
                type = "romfs";
            }
            else if(!strncmp(xsb.xfsb.s_magic, XFS_SUPER_MAGIC, 4)) {
                type = "xfs";
            }
            else if(!strncmp(xsb.qnx4fs_magic+4, "QNX4FS", 6)) {
                type = "qnx4";
            }
            else if(xsb.bfs_magic == 0x1badface) {
                type = "bfs";
            }
            else if(!strncmp(xsb.ntfssb.s_magic, NTFS_SUPER_MAGIC, sizeof xsb.ntfssb.s_magic)) {
                type = "ntfs";
            }
            else if(
                cramfsmagic(xsb.cramfssb) == CRAMFS_SUPER_MAGIC ||
                cramfsmagic(xsb.cramfssb) == CRAMFS_SUPER_MAGIC_BIG
            ) {
                type = "cramfs";
            }
            else if(
                xsb.data[0x1fe] == 0x55 &&
                xsb.data[0x1ff] == 0xaa &&
                xsb.data[0x0b] == 0 &&	/* bytes per sector, bits 0-7 */
                (
                    (	/* FAT12/16 */
                        xsb.data[0x26] == 0x29 && (
                            !strncmp(xsb.fatsb.s_fs, "FAT12   ", 8) ||
                            !strncmp(xsb.fatsb.s_fs, "FAT16   ", 8)
                        )
                    ) ||
                    (	/* FAT32 */
                        xsb.data[0x42] == 0x29 &&
                        !strncmp(xsb.fatsb.s_fs2, "FAT32   ", 8)
                    )
                )
            ) {
                type = "vfat";
            }
        }
    }

    if(!type) {
        char buf[6];

        if(
            lseek(fd, 0, SEEK_SET) == 0 &&
            read(fd, buf, sizeof buf) == sizeof buf
        ) {
            if(!memcmp(buf, "070701", 6) || !memcmp(buf, "\xc7\x71", 2)) type = "cpio";
            else if(!memcmp(buf, "hsqs", 4) || !memcmp(buf, "sqsh", 4)) type = "squashfs";
            else if(!memcmp(buf, "\xed\xab\xee\xdb", 4) && buf[4] >= 3) type = "rpm";
        }
    }

    if(!type) {	/* sector 1 */
        struct sysv_super_block svsb;

        if(
            lseek(fd, 512 , SEEK_SET) == 512 &&
            read(fd, &svsb, sizeof svsb) == sizeof svsb &&
            sysvmagic(svsb) == SYSV_SUPER_MAGIC
        ) {
            type = "sysv";
        }
    }

    if(!type) {	/* block 1 */
        union {
            struct minix_super_block ms;
            struct ext_super_block es;
            struct ext2_super_block e2s;
            struct vxfs_super_block vs;
        } sb;

        if(
            lseek(fd, 1024, SEEK_SET) == 1024 &&
            read(fd, &sb, sizeof sb) == sizeof sb
        ) {
            /*
             * ext2 has magic in little-endian on disk, so "swapped" is
             * superfluous; however, there have existed strange byteswapped
             * PPC ext2 systems
             */
            if(
                ext2magic(sb.e2s) == EXT2_SUPER_MAGIC ||
                ext2magic(sb.e2s) == EXT2_PRE_02B_MAGIC ||
                ext2magic(sb.e2s) == swapped(EXT2_SUPER_MAGIC)
            ) {
                type = "ext2";

                if(
                    (assemble4le(sb.e2s.s_feature_compat) & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
                    assemble4le(sb.e2s.s_journal_inum) != 0
                ) {
                    type = "ext3";

                    if((assemble4le(sb.e2s.s_feature_incompat) & EXT4_FEATURE_INCOMPAT_EXTENTS)) {
                        type = "ext4";
                    }
                }
            }
            else if(
                minixmagic(sb.ms) == MINIX_SUPER_MAGIC ||
                minixmagic(sb.ms) == MINIX_SUPER_MAGIC2 ||
                minixmagic(sb.ms) == MINIX2_SUPER_MAGIC ||
                minixmagic(sb.ms) == MINIX2_SUPER_MAGIC2
            ) {
                type = "minix";
            }
            else if(extmagic(sb.es) == EXT_SUPER_MAGIC) {
                type = "ext";
            }
            else if(vxfsmagic(sb.vs) == VXFS_SUPER_MAGIC) {
                type = "vxfs";
            }
        }
    }

    if(!type) {	/* block 1 */
        struct hfs_super_block hfssb;

        /*
         * also check if block size is equal to 512 bytes,
         * since the hfs driver currently only has support
         * for block sizes of 512 bytes long, and to be
         * more accurate (sb magic is only a short int)
         */
        if(
            lseek(fd, 0x400, SEEK_SET) == 0x400 &&
            read(fd, &hfssb, sizeof hfssb) == sizeof hfssb &&
            (
                (hfsmagic(hfssb) == HFS_SUPER_MAGIC && hfsblksize(hfssb) == 0x20000) ||
                (swapped(hfsmagic(hfssb)) == HFS_SUPER_MAGIC && hfsblksize(hfssb) == 0x200)
            )
        ) {
            type = "hfs";
        }
    }

    if(!type) {	/* block 8 */
        struct ufs_super_block ufssb;

        if(
            lseek(fd, 8192, SEEK_SET) == 8192 &&
            read(fd, &ufssb, sizeof ufssb) == sizeof ufssb &&
            ufsmagic(ufssb) == UFS_SUPER_MAGIC	/* also test swapped version? */
        ) {
            type = "ufs";
        }
    }

    if(!type) {	/* block 8 */
        struct reiserfs_super_block reiserfssb;

        if(
            lseek(fd, REISERFS_OLD_DISK_OFFSET_IN_BYTES, SEEK_SET) == REISERFS_OLD_DISK_OFFSET_IN_BYTES &&
            read(fd, &reiserfssb, sizeof(reiserfssb)) == sizeof(reiserfssb) &&
            is_reiserfs_magic_string(&reiserfssb)
        ) {
            type = "reiserfs";
        }
    }

    if(!type) {	/* block 8 */
        struct hpfs_super_block hpfssb;

        if(
            lseek(fd, 0x2000, SEEK_SET) == 0x2000 &&
            read(fd, &hpfssb, sizeof hpfssb) == sizeof hpfssb &&
            hpfsmagic(hpfssb) == HPFS_SUPER_MAGIC
        ) {
            type = "hpfs";
        }
    }

    if(!type) {	/* block 32 */
        struct jfs_super_block jfssb;

        if(
            lseek(fd, JFS_SUPER1_OFF, SEEK_SET) == JFS_SUPER1_OFF &&
            read(fd, &jfssb, sizeof jfssb) == sizeof jfssb &&
            !strncmp(jfssb.s_magic, JFS_MAGIC, 4)
        ) {
            type = "jfs";
        }
    }

    if(!type) {	/* block 32 */
        union {
            struct iso_volume_descriptor iso;
            struct hs_volume_descriptor hs;
        } isosb;

        if(
            lseek(fd, 0x8000, SEEK_SET) == 0x8000 &&
            read(fd, &isosb, sizeof isosb) == sizeof isosb
        ) {
            if(
                !strncmp(isosb.iso.id, ISO_STANDARD_ID, sizeof(isosb.iso.id)) ||
                !strncmp(isosb.hs.id, HS_STANDARD_ID, sizeof(isosb.hs.id))
            ) {
                type = "iso9660";
            }
            else if(may_be_udf(isosb.iso.id)) {
                type = "udf";
            }
        }
    }

    if(!type) {	/* block 64 */
        struct reiserfs_super_block reiserfssb;

        if(
            lseek(fd, REISERFS_DISK_OFFSET_IN_BYTES, SEEK_SET) == REISERFS_DISK_OFFSET_IN_BYTES &&
            read(fd, &reiserfssb, sizeof reiserfssb) == sizeof reiserfssb &&
            is_reiserfs_magic_string(&reiserfssb)
        ) {
            type = "reiserfs";
        }
    }

    if(!type) {
        char buf[8];

        if(
            lseek(fd, 0x10040, SEEK_SET) == 0x10040 &&
            read(fd, buf, sizeof buf) == sizeof buf &&
            !memcmp(buf, "_BHRfS_M", sizeof buf)
        ) {
            type = "btrfs";
        }
    }

    if(!type) {
        char buf[6];

        if(
            lseek(fd, 0x101, SEEK_SET) == 0x101 &&
            read(fd, buf, sizeof buf) == sizeof buf &&
            !memcmp(buf, "ustar", 6 /* with \0 */)
        ) {
            type = "tar";
        }
    }

    if(!type) {
        /*
         * perhaps the user tries to mount the swap space
         * on a new disk; warn her before she does mke2fs on it
         */
        int pagesize = getpagesize();
        int rd;
        char buf[pagesize + 32768];

        rd = pagesize;
        if(rd < 8192) rd = 8192;
        if(rd > sizeof buf) rd = sizeof buf;
        if(
            lseek(fd, 0, SEEK_SET) == 0 &&
            read(fd, buf, rd) == rd &&
            (
                may_be_swap(buf + pagesize) ||
                may_be_swap(buf + 4096) ||
                may_be_swap(buf + 8192)
            )
        ) {
            type = "swap";
        }
    }

    close(fd);

    return type;
}