2005-01-31 07:28:44 +03:00
/*
* volume_id - reads filesystem label and uuid
*
* Copyright ( C ) 2004 Kay Sievers < kay . sievers @ vrfy . org >
*
2008-09-10 04:40:42 +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 , either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-01-31 07:28:44 +03:00
*/
# ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
# endif
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <string.h>
# include <errno.h>
# include <ctype.h>
2007-04-24 20:35:24 +04:00
# include <byteswap.h>
2005-01-31 07:28:44 +03:00
2006-03-23 12:50:55 +03:00
# include "libvolume_id.h"
2008-08-29 01:39:41 +04:00
# include "libvolume_id-private.h"
2005-01-31 07:28:44 +03:00
2008-05-13 02:55:53 +04:00
struct mdp0_super_block {
2007-04-24 20:35:24 +04:00
uint32_t md_magic ;
2005-08-01 03:33:36 +04:00
uint32_t major_version ;
uint32_t minor_version ;
uint32_t patch_version ;
uint32_t gvalid_words ;
uint32_t set_uuid0 ;
uint32_t ctime ;
uint32_t level ;
uint32_t size ;
uint32_t nr_disks ;
uint32_t raid_disks ;
uint32_t md_minor ;
uint32_t not_persistent ;
uint32_t set_uuid1 ;
uint32_t set_uuid2 ;
uint32_t set_uuid3 ;
2008-05-13 02:55:53 +04:00
} PACKED ;
2007-04-24 20:35:24 +04:00
struct mdp1_super_block {
uint32_t magic ;
uint32_t major_version ;
uint32_t feature_map ;
uint32_t pad0 ;
uint8_t set_uuid [ 16 ] ;
uint8_t set_name [ 32 ] ;
2008-05-13 02:55:53 +04:00
} PACKED ;
2005-02-09 03:02:18 +03:00
2005-01-31 07:28:44 +03:00
# define MD_RESERVED_BYTES 0x10000
2007-04-24 20:35:24 +04:00
# define MD_SB_MAGIC 0xa92b4efc
2005-01-31 07:28:44 +03:00
2007-04-24 20:35:24 +04:00
static int volume_id_probe_linux_raid0 ( struct volume_id * id , uint64_t off , uint64_t size )
2005-01-31 07:28:44 +03:00
{
2005-08-01 03:33:36 +04:00
const uint8_t * buf ;
2008-05-13 02:55:53 +04:00
struct mdp0_super_block * mdp0 ;
2007-04-24 20:35:24 +04:00
union {
uint32_t ints [ 4 ] ;
uint8_t bytes [ 16 ] ;
} uuid ;
2005-01-31 07:28:44 +03:00
2008-10-03 20:24:04 +04:00
info ( " probing at offset 0x% " PRIx64 " , size 0x% " PRIx64 " \n " , off , size ) ;
2005-01-31 07:28:44 +03:00
if ( size < 0x10000 )
return - 1 ;
2007-04-24 20:35:24 +04:00
buf = volume_id_get_buffer ( id , off , 0x800 ) ;
if ( buf = = NULL )
return - 1 ;
mdp0 = ( struct mdp0_super_block * ) buf ;
if ( le32_to_cpu ( mdp0 - > md_magic ) = = MD_SB_MAGIC ) {
uuid . ints [ 0 ] = bswap_32 ( mdp0 - > set_uuid0 ) ;
2007-04-29 01:06:20 +04:00
if ( le32_to_cpu ( mdp0 - > minor_version > = 90 ) ) {
uuid . ints [ 1 ] = bswap_32 ( mdp0 - > set_uuid1 ) ;
uuid . ints [ 2 ] = bswap_32 ( mdp0 - > set_uuid2 ) ;
uuid . ints [ 3 ] = bswap_32 ( mdp0 - > set_uuid3 ) ;
} else {
uuid . ints [ 1 ] = 0 ;
uuid . ints [ 2 ] = 0 ;
uuid . ints [ 3 ] = 0 ;
}
2007-12-16 21:22:32 +03:00
volume_id_set_uuid ( id , uuid . bytes , 0 , UUID_MD ) ;
2007-04-24 20:35:24 +04:00
snprintf ( id - > type_version , sizeof ( id - > type_version ) - 1 , " %u.%u.%u " ,
le32_to_cpu ( mdp0 - > major_version ) ,
le32_to_cpu ( mdp0 - > minor_version ) ,
le32_to_cpu ( mdp0 - > patch_version ) ) ;
} else if ( be32_to_cpu ( mdp0 - > md_magic ) = = MD_SB_MAGIC ) {
uuid . ints [ 0 ] = mdp0 - > set_uuid0 ;
2007-04-29 01:06:20 +04:00
if ( be32_to_cpu ( mdp0 - > minor_version > = 90 ) ) {
uuid . ints [ 1 ] = mdp0 - > set_uuid1 ;
uuid . ints [ 2 ] = mdp0 - > set_uuid2 ;
uuid . ints [ 3 ] = mdp0 - > set_uuid3 ;
} else {
uuid . ints [ 1 ] = 0 ;
uuid . ints [ 2 ] = 0 ;
uuid . ints [ 3 ] = 0 ;
}
2007-12-16 21:22:32 +03:00
volume_id_set_uuid ( id , uuid . bytes , 0 , UUID_MD ) ;
2007-04-24 20:35:24 +04:00
snprintf ( id - > type_version , sizeof ( id - > type_version ) - 1 , " %u.%u.%u " ,
be32_to_cpu ( mdp0 - > major_version ) ,
be32_to_cpu ( mdp0 - > minor_version ) ,
be32_to_cpu ( mdp0 - > patch_version ) ) ;
} else
return - 1 ;
volume_id_set_usage ( id , VOLUME_ID_RAID ) ;
id - > type = " linux_raid_member " ;
return 0 ;
}
static int volume_id_probe_linux_raid1 ( struct volume_id * id , uint64_t off , uint64_t size )
{
const uint8_t * buf ;
2008-05-13 02:55:53 +04:00
struct mdp1_super_block * mdp1 ;
2007-04-24 20:35:24 +04:00
2008-10-03 20:24:04 +04:00
info ( " probing at offset 0x% " PRIx64 " , size 0x% " PRIx64 " \n " , off , size ) ;
2007-04-24 20:35:24 +04:00
buf = volume_id_get_buffer ( id , off , 0x800 ) ;
2005-01-31 07:28:44 +03:00
if ( buf = = NULL )
return - 1 ;
2007-04-24 20:35:24 +04:00
mdp1 = ( struct mdp1_super_block * ) buf ;
2005-01-31 07:28:44 +03:00
2007-04-24 20:35:24 +04:00
if ( le32_to_cpu ( mdp1 - > magic ) ! = MD_SB_MAGIC )
2005-01-31 07:28:44 +03:00
return - 1 ;
2007-12-07 19:26:15 +03:00
if ( le32_to_cpu ( mdp1 - > major_version ) ! = 1 )
return - 1 ;
2007-12-16 21:22:32 +03:00
volume_id_set_uuid ( id , mdp1 - > set_uuid , 0 , UUID_MD ) ;
2007-04-24 20:35:24 +04:00
volume_id_set_label_raw ( id , mdp1 - > set_name , 32 ) ;
volume_id_set_label_string ( id , mdp1 - > set_name , 32 ) ;
2005-01-31 07:28:44 +03:00
volume_id_set_usage ( id , VOLUME_ID_RAID ) ;
id - > type = " linux_raid_member " ;
return 0 ;
}
2007-04-24 20:35:24 +04:00
int volume_id_probe_linux_raid ( struct volume_id * id , uint64_t off , uint64_t size )
{
2007-08-29 08:06:00 +04:00
uint64_t sboff ;
2007-04-24 20:35:24 +04:00
2008-09-06 18:23:21 +04:00
if ( size > MD_RESERVED_BYTES ) {
/* version 0 at the end of the device */
sboff = ( size & ~ ( MD_RESERVED_BYTES - 1 ) ) - MD_RESERVED_BYTES ;
if ( volume_id_probe_linux_raid0 ( id , off + sboff , size ) = = 0 )
return 0 ;
/* version 1.0 at the end of the device */
sboff = ( size & ~ ( 0x1000 - 1 ) ) - 0x2000 ;
if ( volume_id_probe_linux_raid1 ( id , off + sboff , size ) = = 0 ) {
strcpy ( id - > type_version , " 1.0 " ) ;
return 0 ;
}
}
2007-04-24 20:35:24 +04:00
/* version 1.1 at the start of the device */
2008-09-06 18:23:21 +04:00
if ( volume_id_probe_linux_raid1 ( id , off , size ) = = 0 ) {
2007-12-07 19:26:15 +03:00
strcpy ( id - > type_version , " 1.1 " ) ;
2008-09-06 18:23:21 +04:00
return 0 ;
}
2007-04-24 20:35:24 +04:00
/* version 1.2 at 4k offset from the start */
2008-09-06 18:23:21 +04:00
if ( volume_id_probe_linux_raid1 ( id , off + 0x1000 , size ) = = 0 ) {
2007-12-07 19:26:15 +03:00
strcpy ( id - > type_version , " 1.2 " ) ;
2008-09-06 18:23:21 +04:00
return 0 ;
}
2007-04-24 20:35:24 +04:00
2008-09-06 18:23:21 +04:00
return - 1 ;
2007-04-24 20:35:24 +04:00
}