2005-01-31 07:28:44 +03:00
/*
* volume_id - reads filesystem label and uuid
*
2008-02-09 14:17:32 +03:00
* Copyright ( C ) 2004 - 2008 Kay Sievers < kay . sievers @ vrfy . org >
* Copyright ( C ) 2008 Theodore Ts ' o < tytso @ mit . edu >
*
* The probe logic is based on libblkid from e2fsutils .
2005-01-31 07:28:44 +03:00
*
2005-09-27 18:27:35 +04:00
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation version 2 of the License .
2005-01-31 07:28:44 +03:00
*/
# ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
# endif
# ifdef HAVE_CONFIG_H
# include <config.h>
# endif
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <string.h>
# include <errno.h>
# include <ctype.h>
2006-03-23 12:50:55 +03:00
# include "libvolume_id.h"
2005-02-23 04:58:31 +03:00
# include "util.h"
2005-01-31 07:28:44 +03:00
2005-02-09 03:02:18 +03:00
struct ext2_super_block {
2005-10-23 19:41:55 +04:00
uint32_t s_inodes_count ;
uint32_t s_blocks_count ;
uint32_t s_r_blocks_count ;
uint32_t s_free_blocks_count ;
uint32_t s_free_inodes_count ;
uint32_t s_first_data_block ;
uint32_t s_log_block_size ;
uint32_t s_log_frag_size ;
uint32_t s_blocks_per_group ;
uint32_t s_frags_per_group ;
uint32_t s_inodes_per_group ;
uint32_t s_mtime ;
uint32_t s_wtime ;
uint16_t s_mnt_count ;
uint16_t s_max_mnt_count ;
uint16_t s_magic ;
uint16_t s_state ;
uint16_t s_errors ;
uint16_t s_minor_rev_level ;
uint32_t s_lastcheck ;
uint32_t s_checkinterval ;
uint32_t s_creator_os ;
uint32_t s_rev_level ;
uint16_t s_def_resuid ;
uint16_t s_def_resgid ;
uint32_t s_first_ino ;
uint16_t s_inode_size ;
uint16_t s_block_group_nr ;
uint32_t s_feature_compat ;
uint32_t s_feature_incompat ;
uint32_t s_feature_ro_compat ;
uint8_t s_uuid [ 16 ] ;
uint8_t s_volume_name [ 16 ] ;
2008-02-09 14:17:32 +03:00
uint8_t s_last_mounted [ 64 ] ;
uint32_t s_algorithm_usage_bitmap ;
uint8_t s_prealloc_blocks ;
uint8_t s_prealloc_dir_blocks ;
uint16_t s_reserved_gdt_blocks ;
uint8_t s_journal_uuid [ 16 ] ;
uint32_t s_journal_inum ;
uint32_t s_journal_dev ;
uint32_t s_last_orphan ;
uint32_t s_hash_seed [ 4 ] ;
uint8_t s_def_hash_version ;
uint8_t s_jnl_backup_type ;
uint16_t s_reserved_word_pad ;
uint32_t s_default_mount_opts ;
uint32_t s_first_meta_bg ;
uint32_t s_mkfs_time ;
uint32_t s_jnl_blocks [ 17 ] ;
uint32_t s_blocks_count_hi ;
uint32_t s_r_blocks_count_hi ;
uint32_t s_free_blocks_hi ;
uint16_t s_min_extra_isize ;
uint16_t s_want_extra_isize ;
uint32_t s_flags ;
2006-02-21 20:44:18 +03:00
} PACKED ;
2005-02-09 03:02:18 +03:00
2005-10-23 19:41:55 +04:00
# define EXT_SUPER_MAGIC 0xEF53
2008-02-09 14:17:32 +03:00
# define EXT2_FLAGS_TEST_FILESYS 0x0004
# define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
# define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
# define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
# define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
# define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
2007-07-08 19:25:55 +04:00
# define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
# define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008
2008-02-09 14:17:32 +03:00
# define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004
2007-07-08 19:25:55 +04:00
2005-01-31 07:28:44 +03:00
2008-02-09 14:17:32 +03:00
# define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
EXT2_FEATURE_RO_COMPAT_LARGE_FILE | \
EXT2_FEATURE_RO_COMPAT_BTREE_DIR )
# define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT2_FEATURE_RO_COMPAT_SUPP
# define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
EXT2_FEATURE_INCOMPAT_META_BG )
# define EXT2_FEATURE_INCOMPAT_UNSUPPORTED ~EXT2_FEATURE_INCOMPAT_SUPP
# define EXT3_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
EXT2_FEATURE_RO_COMPAT_LARGE_FILE | \
EXT2_FEATURE_RO_COMPAT_BTREE_DIR )
# define EXT3_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT3_FEATURE_RO_COMPAT_SUPP
# define EXT3_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
EXT3_FEATURE_INCOMPAT_RECOVER | \
EXT2_FEATURE_INCOMPAT_META_BG )
# define EXT3_FEATURE_INCOMPAT_UNSUPPORTED ~EXT3_FEATURE_INCOMPAT_SUPP
# define EXT_SUPERBLOCK_OFFSET 0x400
2005-10-23 19:41:55 +04:00
# define EXT3_MIN_BLOCK_SIZE 0x400
# define EXT3_MAX_BLOCK_SIZE 0x1000
2006-07-25 16:59:50 +04:00
int volume_id_probe_ext ( struct volume_id * id , uint64_t off , uint64_t size )
2005-01-31 07:28:44 +03:00
{
2005-02-09 03:02:18 +03:00
struct ext2_super_block * es ;
2005-10-23 19:41:55 +04:00
size_t bsize ;
2007-07-08 19:25:55 +04:00
uint32_t feature_compat ;
2008-02-09 14:17:32 +03:00
uint32_t feature_ro_compat ;
2007-07-08 19:25:55 +04:00
uint32_t feature_incompat ;
2008-02-09 14:17:32 +03:00
uint32_t flags ;
2005-02-09 03:02:18 +03:00
2006-04-08 07:04:35 +04:00
info ( " probing at offset 0x%llx " , ( unsigned long long ) off ) ;
2005-01-31 07:28:44 +03:00
es = ( struct ext2_super_block * ) volume_id_get_buffer ( id , off + EXT_SUPERBLOCK_OFFSET , 0x200 ) ;
if ( es = = NULL )
return - 1 ;
2005-10-23 19:41:55 +04:00
if ( es - > s_magic ! = cpu_to_le16 ( EXT_SUPER_MAGIC ) )
2005-01-31 07:28:44 +03:00
return - 1 ;
2005-10-23 23:12:51 +04:00
bsize = 0x400 < < le32_to_cpu ( es - > s_log_block_size ) ;
dbg ( " ext blocksize 0x%zx " , bsize ) ;
if ( bsize < EXT3_MIN_BLOCK_SIZE | | bsize > EXT3_MAX_BLOCK_SIZE ) {
dbg ( " invalid ext blocksize " ) ;
return - 1 ;
}
2007-07-08 19:25:55 +04:00
feature_compat = le32_to_cpu ( es - > s_feature_compat ) ;
2008-02-09 14:17:32 +03:00
feature_ro_compat = le32_to_cpu ( es - > s_feature_ro_compat ) ;
2007-07-08 19:25:55 +04:00
feature_incompat = le32_to_cpu ( es - > s_feature_incompat ) ;
2008-02-09 14:17:32 +03:00
flags = le32_to_cpu ( es - > s_flags ) ;
2007-07-08 19:25:55 +04:00
2008-02-09 14:17:32 +03:00
/* external journal device is jbd */
2007-07-08 19:25:55 +04:00
if ( ( feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV ) ! = 0 ) {
2005-10-23 19:41:55 +04:00
volume_id_set_usage ( id , VOLUME_ID_OTHER ) ;
id - > type = " jbd " ;
2008-02-09 14:17:32 +03:00
goto found ;
2007-07-08 19:25:55 +04:00
}
2008-02-09 14:17:32 +03:00
/* has journal */
2007-07-08 19:25:55 +04:00
if ( ( feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL ) ! = 0 ) {
2008-02-09 14:17:32 +03:00
/* "use on development code" is ext4dev */
if ( ( flags & EXT2_FLAGS_TEST_FILESYS ) ! = 0 ) {
id - > type = " ext4dev " ;
goto found ;
}
/* incompatible ext3 features is ext4 */
if ( ( feature_ro_compat & EXT3_FEATURE_RO_COMPAT_UNSUPPORTED ) ! = 0 | |
( feature_incompat & EXT3_FEATURE_INCOMPAT_UNSUPPORTED ) ! = 0 ) {
id - > type = " ext4 " ;
goto found ;
}
2005-01-31 07:28:44 +03:00
id - > type = " ext3 " ;
2008-02-09 14:17:32 +03:00
goto found ;
} else {
/* no incompatible ext2 feature is ext2 */
if ( ( feature_ro_compat & EXT2_FEATURE_RO_COMPAT_UNSUPPORTED ) = = 0 & &
( feature_incompat & EXT2_FEATURE_INCOMPAT_UNSUPPORTED ) = = 0 ) {
id - > type = " ext2 " ;
goto found ;
}
2007-07-08 19:25:55 +04:00
}
2008-02-09 14:17:32 +03:00
return - 1 ;
found :
volume_id_set_label_raw ( id , es - > s_volume_name , 16 ) ;
volume_id_set_label_string ( id , es - > s_volume_name , 16 ) ;
volume_id_set_uuid ( id , es - > s_uuid , 0 , UUID_DCE ) ;
snprintf ( id - > type_version , sizeof ( id - > type_version ) - 1 , " %u.%u " ,
le32_to_cpu ( es - > s_rev_level ) , le16_to_cpu ( es - > s_minor_rev_level ) ) ;
2005-01-31 07:28:44 +03:00
2008-02-09 14:17:32 +03:00
volume_id_set_usage ( id , VOLUME_ID_FILESYSTEM ) ;
2005-01-31 07:28:44 +03:00
return 0 ;
}