/* * 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; }
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; }