@ -16,25 +16,25 @@
* along with this program . If not , see < http : // www.gnu.org/licenses/>.
*/
# include <map>
# include <list>
# include <string>
# include <vector>
# include <dirent.h>
# include <errno.h>
# include <fcntl.h>
# include <limits.h>
# include <list>
# include <map>
# include <regex>
# include <stdint.h>
# include <stdio.h>
# include <string.h>
# include <unistd.h>
# include <dirent.h>
# include <sys/types.h>
# include <string>
# include <sys/stat.h>
# include <fcntl .h>
# include <limits .h>
# include <stdint.h >
# include <sys/types.h>
# include <unistd .h>
# include <vector >
# include "utils.h"
# include "gpt-utils.h"
# include "ufs-bsg.h"
# include "utils.h"
# include "bootctrl.h"
@ -54,8 +54,7 @@
* ( pentry + AB_FLAG_OFFSET ) = AB_SLOT_ACTIVE_VAL ; \
else if ( slot_state = = SLOT_INACTIVE ) \
* ( pentry + AB_FLAG_OFFSET ) = \
( * ( pentry + AB_FLAG_OFFSET ) & \
~ AB_PARTITION_ATTR_SLOT_ACTIVE ) ; \
( * ( pentry + AB_FLAG_OFFSET ) & ~ AB_PARTITION_ATTR_SLOT_ACTIVE ) ; \
} )
using namespace std ;
@ -76,8 +75,7 @@ void get_kernel_cmdline_arg(const char *arg, char *buf, const char *def)
fd = open ( " /proc/cmdline " , O_RDONLY ) ;
int rc = read ( fd , pcmd , MAX_CMDLINE_SIZE ) ;
if ( rc < 0 ) {
fprintf ( stderr , " Couldn't open /proc/cmdline: %d (%s) \n " , rc ,
strerror ( errno ) ) ;
fprintf ( stderr , " Couldn't open /proc/cmdline: %d (%s) \n " , rc , strerror ( errno ) ) ;
goto error ;
}
close ( fd ) ;
@ -100,132 +98,136 @@ error:
}
// Get the value of one of the attribute fields for a partition.
static int get_partition_attribute ( char * partname ,
static int get_partition_attribute ( struct gpt_disk * disk , char * partname ,
enum part_attr_type part_attr )
{
struct gpt_disk * disk = NULL ;
uint8_t * pentry = NULL ;
uint8_t * pentry = nullptr ;
int retval = - 1 ;
uint8_t * attr = NULL ;
uint8_t * attr = nullptr ;
if ( ! partname )
goto error ;
disk = gpt_disk_alloc ( ) ;
if ( ! disk ) {
fprintf ( stderr , " %s: Failed to alloc disk struct \n " , __func__ ) ;
goto error ;
}
if ( gpt_disk_get_disk_info ( partname , disk ) ) {
fprintf ( stderr , " %s: Failed to get disk info \n " , __func__ ) ;
goto error ;
return - 1 ;
// Will initialise the disk if null, or reinitialise it if
// it's for a partition on a different disk
if ( gpt_disk_get_disk_info ( partname , disk ) < 0 ) {
fprintf ( stderr , " %s: gpt_disk_get_disk_info failed \n " , __func__ ) ;
return - 1 ;
}
pentry = gpt_disk_get_pentry ( disk , partname , PRIMARY_GPT ) ;
if ( ! pentry ) {
fprintf ( stderr , " %s: pentry does not exist in disk struct \n " ,
__func__ ) ;
goto error ;
fprintf ( stderr , " %s: pentry does not exist in disk struct \n " , __func__ ) ;
return - 1 ;
}
attr = pentry + AB_FLAG_OFFSET ;
LOGD ( " get_partition_attribute () partname = %s, attr = 0x%x\n " , partname ,
* attr ) ;
if ( part_attr = = ATTR_SLOT_ACTIVE ) {
LOGD ( " %s () partname = %s, attr = 0x%x\n " , __func__ , partname , * attr ) ;
switch ( part_attr ) {
case ATTR_SLOT_ACTIVE :
retval = ! ! ( * attr & AB_PARTITION_ATTR_SLOT_ACTIVE ) ;
LOGD ( " ATTR_SLOT_ACTIVE, retval = %d \n " , retval ) ;
} else if ( part_attr = = ATTR_BOOT_SUCCESSFUL ) {
break ;
case ATTR_BOOT_SUCCESSFUL :
retval = ! ! ( * attr & AB_PARTITION_ATTR_BOOT_SUCCESSFUL ) ;
LOGD ( " AB_PARTITION_ATTR_BOOT_SUCCESSFUL, retval = %d \n " ,
retval ) ;
} else if ( part_attr = = ATTR_UNBOOTABLE ) {
LOGD ( " AB_PARTITION_ATTR_BOOT_SUCCESSFUL, retval = %d \n " , retval ) ;
break ;
case ATTR_UNBOOTABLE :
retval = ! ! ( * attr & AB_PARTITION_ATTR_UNBOOTABLE ) ;
LOGD ( " AB_PARTITION_ATTR_UNBOOTABLE, retval = %d \n " , retval ) ;
} else {
break ;
default :
retval = - 1 ;
}
gpt_disk_free ( disk ) ;
return retval ;
error :
if ( disk )
gpt_disk_free ( disk ) ;
return retval ;
}
// Set a particular attribute for all the partitions in a
// slot
static int update_slot_attribute ( const char * slot , enum part_attr_type ab_attr )
static int update_slot_attribute ( struct gpt_disk * disk , const char * slot ,
enum part_attr_type ab_attr )
{
unsigned int i = 0 ;
char buf [ PATH_MAX ] ;
struct stat st ;
struct gpt_disk * disk = NULL ;
uint8_t * pentry = NULL ;
uint8_t * pentry_bak = NULL ;
uint8_t * pentry = nullptr ;
uint8_t * pentry_bak = nullptr ;
int rc = - 1 ;
uint8_t * attr = NULL ;
uint8_t * attr_bak = NULL ;
uint8_t * attr = nullptr ;
uint8_t * attr_bak = nullptr ;
char partName [ MAX_GPT_NAME_SIZE + 1 ] = { 0 } ;
const char ptn_list [ ] [ MAX_GPT_NAME_SIZE - 1 ] = { AB_PTN_LIST } ;
static const char ptn_list [ ] [ MAX_GPT_NAME_SIZE - 1 ] = { AB_PTN_LIST } ;
int slot_name_valid = 0 ;
char devpath [ PATH_MAX ] = { 0 } ;
if ( ! slot ) {
fprintf ( stderr , " %s: Invalid argument \n " , __func__ ) ;
goto error ;
return - 1 ;
}
for ( i = 0 ; slot_suffix_arr [ i ] ! = NULL ; i + + ) {
if ( ! strncmp ( slot , slot_suffix_arr [ i ] ,
strlen ( slot_suffix_arr [ i ] ) ) )
for ( i = 0 ; slot_suffix_arr [ i ] ! = nullptr ; i + + ) {
if ( ! strncmp ( slot , slot_suffix_arr [ i ] , strlen ( slot_suffix_arr [ i ] ) ) )
slot_name_valid = 1 ;
}
if ( ! slot_name_valid ) {
fprintf ( stderr , " %s: Invalid slot name \n " , __func__ ) ;
goto error ;
return - 1 ;
}
for ( i = 0 ; i < ARRAY_SIZE ( ptn_list ) ; i + + ) {
memset ( buf , ' \0 ' , sizeof ( buf ) ) ;
// Check if A/B versions of this ptn exist
snprintf ( buf , sizeof ( buf ) - 1 , " %s/%s%s " , BOOT_DEV_DIR ,
ptn_list [ i ] , AB_SLOT_A_SUFFIX ) ;
snprintf ( buf , sizeof ( buf ) - 1 , " %s/%s%s " , BOOT_DEV_DIR , ptn_list [ i ] ,
AB_SLOT_A_SUFFIX ) ;
if ( stat ( buf , & st ) < 0 ) {
// partition does not have _a version
continue ;
}
memset ( buf , ' \0 ' , sizeof ( buf ) ) ;
snprintf ( buf , sizeof ( buf ) - 1 , " %s/%s%s " , BOOT_DEV_DIR ,
ptn_list [ i ] , AB_SLOT_B_SUFFIX ) ;
snprintf ( buf , sizeof ( buf ) - 1 , " %s/%s%s " , BOOT_DEV_DIR , ptn_list [ i ] ,
AB_SLOT_B_SUFFIX ) ;
if ( stat ( buf , & st ) < 0 ) {
// partition does not have _b version
continue ;
}
memset ( partName , ' \0 ' , sizeof ( partName ) ) ;
snprintf ( partName , sizeof ( partName ) - 1 , " %s%s " , ptn_list [ i ] ,
slot ) ;
disk = gpt_disk_alloc ( ) ;
if ( ! disk ) {
fprintf ( stderr , " %s: Failed to alloc disk struct \n " ,
__func__ ) ;
goto error ;
snprintf ( partName , sizeof ( partName ) - 1 , " %s%s " , ptn_list [ i ] , slot ) ;
// If the current partition is for a different disk (e.g. /dev/sde when the current disk is /dev/sda)
// Then commit the current disk
if ( ! partition_is_for_disk ( partName , disk , devpath , sizeof ( devpath ) ) ) {
if ( ! gpt_disk_commit ( disk ) ) {
fprintf ( stderr , " %s: Failed to commit disk \n " , __func__ ) ;
return - 1 ;
}
}
rc = gpt_disk_get_disk_info ( partName , disk ) ;
if ( rc ! = 0 ) {
fprintf ( stderr , " %s: Failed to get disk info for %s \n " ,
__func__ , partName ) ;
goto error ;
fprintf ( stderr , " %s: Failed to get disk info for %s \n " , __func__ , partName ) ;
return - 1 ;
}
pentry = gpt_disk_get_pentry ( disk , partName , PRIMARY_GPT ) ;
pentry_bak = gpt_disk_get_pentry ( disk , partName , SECONDARY_GPT ) ;
if ( ! pentry | | ! pentry_bak ) {
fprintf ( stderr ,
" %s: Failed to get pentry/pentry_bak for %s \n " ,
__func__ , partName ) ;
goto error ;
fprintf ( stderr , " %s: Failed to get pentry/pentry_bak for %s \n " , __func__ ,
partName ) ;
return - 1 ;
}
attr = pentry + AB_FLAG_OFFSET ;
LOGD ( " %s: got pentry for part '%s': 0x%lx (at flags: 0x%x) \n " ,
__func__ , partName , * ( uint64_t * ) pentry , * attr ) ;
LOGD ( " %s: got pentry for part '%s': 0x%lx (at flags: 0x%x) \n " , __func__ , partName ,
* ( uint64_t * ) pentry , * attr ) ;
attr_bak = pentry_bak + AB_FLAG_OFFSET ;
switch ( ab_attr ) {
case ATTR_BOOT_SUCCESSFUL :
* attr = ( * attr ) | AB_PARTITION_ATTR_BOOT_SUCCESSFUL ;
* attr_bak =
( * attr_bak ) | AB_PARTITION_ATTR_BOOT_SUCCESSFUL ;
* attr_bak = ( * attr_bak ) | AB_PARTITION_ATTR_BOOT_SUCCESSFUL ;
break ;
case ATTR_UNBOOTABLE :
* attr = ( * attr ) | AB_PARTITION_ATTR_UNBOOTABLE ;
@ -241,64 +243,89 @@ static int update_slot_attribute(const char *slot, enum part_attr_type ab_attr)
break ;
default :
fprintf ( stderr , " %s: Unrecognized attr \n " , __func__ ) ;
goto error ;
return - 1 ;
}
if ( gpt_disk_update_crc ( disk ) ) {
fprintf ( stderr , " %s: Failed to update crc for %s \n " ,
__func__ , partName ) ;
goto error ;
}
if ( gpt_disk_commit ( disk ) ) {
fprintf ( stderr ,
" %s: Failed to write back entry for %s \n " ,
__func__ , partName ) ;
goto error ;
}
gpt_disk_free ( disk ) ;
disk = NULL ;
fprintf ( stderr , " %s: Failed to write back entry for %s \n " , __func__ ,
partName ) ;
return - 1 ;
}
return 0 ;
error :
if ( disk )
gpt_disk_free ( disk ) ;
return - 1 ;
}
/*
* Returns 0 for no slots , or the number of slots found .
* Fun semantic note : Having " 1 " slot ( ie just a " boot " partition )
* is the same as having " no slots " .
*
* This function will never return 1.
*/
unsigned get_number_slots ( )
{
struct dirent * de = NULL ;
DIR * dir_bootdev = NULL ;
unsigned slot_count = 0 ;
struct dirent * de = nullptr ;
DIR * dir_bootdev = nullptr ;
static int slot_count = 0 ;
// If we've already counted the slots, return the cached value.
// If there are no slots then we'll always rerun the search...
if ( slot_count > 0 )
return slot_count ;
static_assert ( AB_SLOT_A_SUFFIX [ 0 ] = = ' _ ' , " Breaking change to slot A suffix " ) ;
static_assert ( AB_SLOT_B_SUFFIX [ 0 ] = = ' _ ' , " Breaking change to slot B suffix " ) ;
dir_bootdev = opendir ( BOOTDEV_DIR ) ;
// Shouldn't this be an assert?
if ( ! dir_bootdev ) {
fprintf ( stderr , " %s: Failed to open bootdev dir (%s) \n " ,
__func__ , strerror ( errno ) ) ;
goto error ;
fprintf ( stderr , " %s: Failed to open bootdev dir (%s) \n " , __func__ , strerror ( errno ) ) ;
return 0 ;
}
while ( ( de = readdir ( dir_bootdev ) ) ) {
if ( de - > d_name [ 0 ] = = ' . ' )
continue ;
static_assert ( AB_SLOT_A_SUFFIX [ 0 ] = = ' _ ' ,
" Breaking change to slot A suffix " ) ;
static_assert ( AB_SLOT_B_SUFFIX [ 0 ] = = ' _ ' ,
" Breaking change to slot B suffix " ) ;
if ( ! strncmp ( de - > d_name , BOOT_IMG_PTN_NAME ,
strlen ( BOOT_IMG_PTN_NAME ) ) & &
! ! strncmp ( de - > d_name , " boot_aging \n " ,
strlen ( " boot_aging " ) ) ) {
if ( ! strncmp ( de - > d_name , BOOT_IMG_PTN_NAME , strlen ( BOOT_IMG_PTN_NAME ) ) & &
! ! strncmp ( de - > d_name , " boot_aging \n " , strlen ( " boot_aging " ) ) ) {
slot_count + + ;
}
}
if ( slot_count < 0 )
slot_count = 0 ;
closedir ( dir_bootdev ) ;
return slot_count ;
error :
if ( dir_bootdev )
closedir ( dir_bootdev ) ;
}
static int boot_control_check_slot_sanity ( unsigned slot )
{
uint32_t num_slots = get_number_slots ( ) ;
if ( ( num_slots < 1 ) | | ( slot > num_slots - 1 ) ) {
fprintf ( stderr , " Invalid slot number %u \n " , slot ) ;
return - 1 ;
}
return 0 ;
}
static unsigned int get_current_slot ( )
int get_boot_attr ( struct gpt_disk * disk , unsigned slot , enum part_attr_type attr )
{
char bootPartition [ MAX_GPT_NAME_SIZE + 1 ] = { 0 } ;
if ( boot_control_check_slot_sanity ( slot ) ! = 0 ) {
fprintf ( stderr , " %s: Argument check failed \n " , __func__ ) ;
return - 1 ;
}
snprintf ( bootPartition , sizeof ( bootPartition ) - 1 , " boot%s " , slot_suffix_arr [ slot ] ) ;
return get_partition_attribute ( disk , bootPartition , attr ) ;
}
static unsigned int get_current_slot_from_kernel_cmdline ( )
{
uint32_t num_slots = 0 ;
char bootSlotProp [ MAX_CMDLINE_SIZE ] = { ' \0 ' } ;
@ -308,56 +335,34 @@ static unsigned int get_current_slot()
// Slot 0 is the only slot around.
return 0 ;
}
get_kernel_cmdline_arg ( BOOT_SLOT_PROP , bootSlotProp , " _a " ) ;
if ( ! strncmp ( bootSlotProp , " N/A \n " , strlen ( " N/A " ) ) ) {
fprintf ( stderr , " %s: Unable to read boot slot property \n " ,
__func__ ) ;
goto error ;
fprintf ( stderr , " %s: Unable to read boot slot property \n " , __func__ ) ;
return 0 ;
}
// Iterate through a list of partitons named as boot+suffix
// and see which one is currently active.
for ( i = 0 ; slot_suffix_arr [ i ] ! = NULL ; i + + ) {
if ( ! strncmp ( bootSlotProp , slot_suffix_arr [ i ] ,
strlen ( slot_suffix_arr [ i ] ) ) ) {
for ( i = 0 ; slot_suffix_arr [ i ] ! = nullptr ; i + + ) {
if ( ! strncmp ( bootSlotProp , slot_suffix_arr [ i ] , strlen ( slot_suffix_arr [ i ] ) ) ) {
// printf("%s current_slot = %d\n", __func__, i);
return i ;
}
}
error :
// The HAL spec requires that we return a number between
// 0 to num_slots - 1. Since something went wrong here we
// are just going to return the default slot.
return 0 ;
}
static int boot_control_check_slot_sanity ( unsigned slot )
{
uint32_t num_slots = get_number_slots ( ) ;
if ( ( num_slots < 1 ) | | ( slot > num_slots - 1 ) ) {
fprintf ( stderr , " Invalid slot number " ) ;
return - 1 ;
}
return 0 ;
}
int get_boot_attr ( unsigned slot , enum part_attr_type attr )
{
char bootPartition [ MAX_GPT_NAME_SIZE + 1 ] = { 0 } ;
if ( boot_control_check_slot_sanity ( slot ) ! = 0 ) {
fprintf ( stderr , " %s: Argument check failed \n " , __func__ ) ;
return - 1 ;
}
snprintf ( bootPartition , sizeof ( bootPartition ) - 1 , " boot%s " ,
slot_suffix_arr [ slot ] ) ;
return get_partition_attribute ( bootPartition , attr ) ;
}
int is_slot_bootable ( unsigned slot )
{
int attr = 0 ;
attr = get_boot_attr ( slot , ATTR_UNBOOTABLE ) ;
struct gpt_disk disk = { 0 } ;
attr = get_boot_attr ( & disk , slot , ATTR_UNBOOTABLE ) ;
if ( attr > = 0 )
return ! attr ;
@ -366,30 +371,38 @@ int is_slot_bootable(unsigned slot)
int mark_boot_successful ( unsigned slot )
{
int successful = get_boot_attr ( slot , ATTR_BOOT_SUCCESSFUL ) ;
struct gpt_disk disk = { 0 } ;
int successful = get_boot_attr ( & disk , slot , ATTR_BOOT_SUCCESSFUL ) ;
int bootable = get_boot_attr ( & disk , slot , ATTR_UNBOOTABLE ) ;
int ret = 0 ;
if ( successful < 0 | | bootable < 0 ) {
fprintf ( stderr , " SLOT %s: Failed to read attributes \n " , slot_suffix_arr [ slot ] ) ;
ret = - 1 ;
goto out ;
}
if ( ! is_slot_bootable ( slot ) ) {
printf ( " SLOT %s: was marked unbootable, fixing this "
" (I hope you know what you're doing...) \n " ,
slot_suffix_arr [ slot ] ) ;
update_slot_attribute ( slot_suffix_arr [ slot ] , ATTR_BOOTABLE ) ;
update_slot_attribute ( & disk , slot_suffix_arr [ slot ] , ATTR_BOOTABLE ) ;
}
if ( successful ) {
fprintf ( stderr , " SLOT %s: already marked successful \n " ,
slot_suffix_arr [ slot ] ) ;
return 0 ;
fprintf ( stderr , " SLOT %s: already marked successful \n " , slot_suffix_arr [ slot ] ) ;
goto out ;
}
if ( update_slot_attribute ( slot_suffix_arr [ slot ] ,
ATTR_BOOT_SUCCESSFUL ) ) {
goto error ;
if ( update_slot_attribute ( & disk , slot_suffix_arr [ slot ] , ATTR_BOOT_SUCCESSFUL ) ) {
fprintf ( stderr , " SLOT %s: Failed to mark boot successful \n " , slot_suffix_arr [ slot ] ) ;
ret = - 1 ;
goto out ;
}
return 0 ;
error :
fprintf ( stderr , " SLOT %s: Failed to mark boot successful \n " ,
slot_suffix_arr [ slot ] ) ;
return - 1 ;
out :
gpt_disk_free ( & disk ) ;
return ret ;
}
const char * get_suffix ( unsigned slot )
@ -400,96 +413,67 @@ const char *get_suffix(unsigned slot)
return slot_suffix_arr [ slot ] ;
}
//Return a gpt disk structure representing the disk that holds
//partition.
static struct gpt_disk * boot_ctl_get_disk_info ( char * partition )
{
struct gpt_disk * disk = NULL ;
if ( ! partition )
return NULL ;
disk = gpt_disk_alloc ( ) ;
if ( ! disk ) {
fprintf ( stderr , " %s: Failed to alloc disk \n " , __func__ ) ;
goto error ;
}
if ( gpt_disk_get_disk_info ( partition , disk ) ) {
fprintf ( stderr , " failed to get disk info for %s \n " , partition ) ;
goto error ;
}
return disk ;
error :
if ( disk )
gpt_disk_free ( disk ) ;
return NULL ;
}
// The argument here is a vector of partition names(including the slot suffix)
// that lie on a single disk
static int boot_ctl_set_active_slot_for_partitions ( vector < string > part_list ,
static int boot_ctl_set_active_slot_for_partitions ( struct gpt_disk * disk , vector < string > part_list ,
unsigned slot )
{
char buf [ PATH_MAX ] = { 0 } ;
struct gpt_disk * disk = NULL ;
char slotA [ MAX_GPT_NAME_SIZE + 1 ] = { 0 } ;
char slotB [ MAX_GPT_NAME_SIZE + 1 ] = { 0 } ;
char active_guid [ TYPE_GUID_SIZE + 1 ] = { 0 } ;
char inactive_guid [ TYPE_GUID_SIZE + 1 ] = { 0 } ;
int rc ;
// Pointer to the partition entry of current 'A' partition
uint8_t * pentryA = NULL ;
uint8_t * pentryA_bak = NULL ;
uint8_t * pentryA = nullptr ;
uint8_t * pentryA_bak = nullptr ;
// Pointer to partition entry of current 'B' partition
uint8_t * pentryB = NULL ;
uint8_t * pentryB_bak = NULL ;
uint8_t * pentryB = nullptr ;
uint8_t * pentryB_bak = nullptr ;
struct stat st ;
vector < string > : : iterator partition_iterator ;
LOGD ( " Marking slot %s as active: \n " , slot_suffix_arr [ slot ] ) ;
for ( partition_iterator = part_list . begin ( ) ;
partition_iterator ! = part_list . end ( ) ; partition_iterator + + ) {
for ( partition_iterator = part_list . begin ( ) ; partition_iterator ! = part_list . end ( ) ;
partition_iterator + + ) {
// Chop off the slot suffix from the partition name to
// make the string easier to work with.
string prefix = * partition_iterator ;
LOGD ( " Part: %s \n " , prefix . c_str ( ) ) ;
if ( prefix . size ( ) < ( strlen ( AB_SLOT_A_SUFFIX ) + 1 ) ) {
fprintf ( stderr , " Invalid partition name: %s \n " ,
prefix . c_str ( ) ) ;
goto error ;
fprintf ( stderr , " Invalid partition name: %s \n " , prefix . c_str ( ) ) ;
return - 1 ;
}
prefix . resize ( prefix . size ( ) - strlen ( AB_SLOT_A_SUFFIX ) ) ;
// Check if A/B versions of this ptn exist
snprintf ( buf , sizeof ( buf ) - 1 , " %s/%s%s " , BOOT_DEV_DIR ,
prefix . c_str ( ) , AB_SLOT_A_SUFFIX ) ;
snprintf ( buf , sizeof ( buf ) - 1 , " %s/%s%s " , BOOT_DEV_DIR , prefix . c_str ( ) ,
AB_SLOT_A_SUFFIX ) ;
LOGD ( " \t _a Path: '%s' \n " , buf ) ;
rc = stat ( buf , & st ) ;
if ( rc < 0 ) {
fprintf ( stderr , " Failed to stat() path: %d: %s \n " , rc ,
strerror ( errno ) ) ;
fprintf ( stderr , " Failed to stat() path: %d: %s \n " , rc , strerror ( errno ) ) ;
continue ;
}
memset ( buf , ' \0 ' , sizeof ( buf ) ) ;
snprintf ( buf , sizeof ( buf ) - 1 , " %s/%s%s " , BOOT_DEV_DIR ,
prefix . c_str ( ) , AB_SLOT_B_SUFFIX ) ;
LOGD ( " \t _b Path: '%s' \n " , buf ) ;
snprintf ( buf , sizeof ( buf ) - 1 , " %s/%s%s " , BOOT_DEV_DIR , prefix . c_str ( ) ,
AB_SLOT_B_SUFFIX ) ;
// LOGD("\t_b Path: '%s'\n", buf);
rc = stat ( buf , & st ) ;
if ( rc < 0 ) {
fprintf ( stderr , " Failed to stat() path: %d: %s \n " , rc ,
strerror ( errno ) ) ;
fprintf ( stderr , " Failed to stat() path: %d: %s \n " , rc , strerror ( errno ) ) ;
continue ;
}
memset ( slotA , 0 , sizeof ( slotA ) ) ;
memset ( slotB , 0 , sizeof ( slotA ) ) ;
snprintf ( slotA , sizeof ( slotA ) - 1 , " %s%s " , prefix . c_str ( ) ,
AB_SLOT_A_SUFFIX ) ;
snprintf ( slotB , sizeof ( slotB ) - 1 , " %s%s " , prefix . c_str ( ) ,
AB_SLOT_B_SUFFIX ) ;
snprintf ( slotA , sizeof ( slotA ) - 1 , " %s%s " , prefix . c_str ( ) , AB_SLOT_A_SUFFIX ) ;
snprintf ( slotB , sizeof ( slotB ) - 1 , " %s%s " , prefix . c_str ( ) , AB_SLOT_B_SUFFIX ) ;
// Get the disk containing the partitions that were passed in.
// All partitions passed in must lie on the same disk.
if ( ! disk ) {
disk = boot_ctl_get_disk_info ( slotA ) ;
if ( ! disk )
goto error ;
if ( ! gpt_disk_is_valid ( disk ) ) {
if ( gpt_disk_get_disk_info ( slotA , disk ) < 0 )
return - 1 ;
}
// Get partition entry for slot A & B from the primary
// and backup tables.
@ -500,98 +484,75 @@ static int boot_ctl_set_active_slot_for_partitions(vector<string> part_list,
if ( ! pentryA | | ! pentryA_bak | | ! pentryB | | ! pentryB_bak ) {
// None of these should be NULL since we have already
// checked for A & B versions earlier.
fprintf ( stderr , " Slot pentries for %s not found. \n " ,
prefix . c_str ( ) ) ;
goto error ;
fprintf ( stderr , " Slot pentries for %s not found. \n " , prefix . c_str ( ) ) ;
return - 1 ;
}
LOGD ( " \t AB attr (A): 0x%x (backup: 0x%x) \n " ,
* ( uint16_t * ) ( pentryA + AB_FLAG_OFFSET ) ,
LOGD ( " \t AB attr (A): 0x%x (backup: 0x%x) \n " , * ( uint16_t * ) ( pentryA + AB_FLAG_OFFSET ) ,
* ( uint16_t * ) ( pentryA_bak + AB_FLAG_OFFSET ) ) ;
LOGD ( " \t AB attr (B): 0x%x (backup: 0x%x) \n " ,
* ( uint16_t * ) ( pentryB + AB_FLAG_OFFSET ) ,
LOGD ( " \t AB attr (B): 0x%x (backup: 0x%x) \n " , * ( uint16_t * ) ( pentryB + AB_FLAG_OFFSET ) ,
* ( uint16_t * ) ( pentryB_bak + AB_FLAG_OFFSET ) ) ;
memset ( active_guid , ' \0 ' , sizeof ( active_guid ) ) ;
memset ( inactive_guid , ' \0 ' , sizeof ( inactive_guid ) ) ;
if ( get_partition_attribute ( slotA , ATTR_SLOT_ACTIVE ) = = 1 ) {
if ( get_partition_attribute ( disk , slotA , ATTR_SLOT_ACTIVE ) = = 1 ) {
// A is the current active slot
memcpy ( ( void * ) active_guid , ( const void * ) pentryA ,
TYPE_GUID_SIZE ) ;
memcpy ( ( void * ) inactive_guid , ( const void * ) pentryB ,
TYPE_GUID_SIZE ) ;
} else if ( get_partition_attribute ( slotB , ATTR_SLOT_ACTIVE ) = =
1 ) {
memcpy ( ( void * ) active_guid , ( const void * ) pentryA , TYPE_GUID_SIZE ) ;
memcpy ( ( void * ) inactive_guid , ( const void * ) pentryB , TYPE_GUID_SIZE ) ;
} else if ( get_partition_attribute ( disk , slotB , ATTR_SLOT_ACTIVE ) = = 1 ) {
// B is the current active slot
memcpy ( ( void * ) active_guid , ( const void * ) pentryB ,
TYPE_GUID_SIZE ) ;
memcpy ( ( void * ) inactive_guid , ( const void * ) pentryA ,
TYPE_GUID_SIZE ) ;
memcpy ( ( void * ) active_guid , ( const void * ) pentryB , TYPE_GUID_SIZE ) ;
memcpy ( ( void * ) inactive_guid , ( const void * ) pentryA , TYPE_GUID_SIZE ) ;
} else {
fprintf ( stderr , " Both A & B are inactive..Aborting " ) ;
goto error ;
return - 1 ;
}
// printf("\tActive GUID: %s\n", active_guid);
// printf("\tInactive GUID: %s\n", active_guid);
if ( ! strncmp ( slot_suffix_arr [ slot ] , AB_SLOT_A_SUFFIX ,
strlen ( AB_SLOT_A_SUFFIX ) ) ) {
int a_state = slot = = 0 ? SLOT_ACTIVE : SLOT_INACTIVE ;
int b_state = slot = = 1 ? SLOT_ACTIVE : SLOT_INACTIVE ;
// This check *Really* shouldn't be here... But I don't know this codebase
// well enough to remove it.
if ( slot > 1 ) {
fprintf ( stderr , " %s: Unknown slot %d! \n " , __func__ , slot ) ;
return - 1 ;
}
// Mark A as active in primary table
UPDATE_SLOT ( pentryA , active_guid , SLOT_ACTIVE ) ;
UPDATE_SLOT ( pentryA , active_guid , a_state ) ;
// Mark A as active in backup table
UPDATE_SLOT ( pentryA_bak , active_guid , SLOT_ACTIVE ) ;
UPDATE_SLOT ( pentryA_bak , active_guid , a_state ) ;
// Mark B as inactive in primary table
UPDATE_SLOT ( pentryB , inactive_guid , SLOT_INACTIVE ) ;
UPDATE_SLOT ( pentryB , inactive_guid , b_state ) ;
// Mark B as inactive in backup table
UPDATE_SLOT ( pentryB_bak , inactive_guid , SLOT_INACTIVE ) ;
} else if ( ! strncmp ( slot_suffix_arr [ slot ] , AB_SLOT_B_SUFFIX ,
strlen ( AB_SLOT_B_SUFFIX ) ) ) {
//Mark B as active in primary table
UPDATE_SLOT ( pentryB , active_guid , SLOT_ACTIVE ) ;
//Mark B as active in backup table
UPDATE_SLOT ( pentryB_bak , active_guid , SLOT_ACTIVE ) ;
//Mark A as inavtive in primary table
UPDATE_SLOT ( pentryA , inactive_guid , SLOT_INACTIVE ) ;
//Mark A as inactive in backup table
UPDATE_SLOT ( pentryA_bak , inactive_guid , SLOT_INACTIVE ) ;
} else {
//Something has gone terribly terribly wrong
fprintf ( stderr , " %s: Unknown slot suffix! \n " , __func__ ) ;
goto error ;
}
if ( gpt_disk_update_crc ( disk ) ! = 0 ) {
fprintf ( stderr , " %s: Failed to update gpt_disk crc \n " ,
__func__ ) ;
goto error ;
}
UPDATE_SLOT ( pentryB_bak , inactive_guid , b_state ) ;
}
// write updated content to disk
if ( disk ) {
if ( gpt_disk_commit ( disk ) ) {
fprintf ( stderr , " Failed to commit disk entry " ) ;
goto error ;
}
gpt_disk_free ( disk ) ;
return - 1 ;
}
return 0 ;
error :
if ( disk )
gpt_disk_free ( disk ) ;
return - 1 ;
return 0 ;
}
unsigned get_active_boot_slot ( )
{
struct gpt_disk disk = { 0 } ;
uint32_t num_slots = get_number_slots ( ) ;
if ( num_slots < = 1 ) {
// Slot 0 is the only slot around.
return 0 ;
}
for ( uint32_t i = 0 ; i < num_slots ; i + + ) {
if ( get_boot_attr ( i , ATTR_SLOT_ACTIVE ) )
if ( get_boot_attr ( & disk , i , ATTR_SLOT_ACTIVE ) ) {
gpt_disk_free ( & disk ) ;
return i ;
}
}
fprintf ( stderr , " %s: Failed to find the active boot slot \n " , __func__ ) ;
gpt_disk_free ( & disk ) ;
return 0 ;
}
@ -600,6 +561,7 @@ int set_active_boot_slot(unsigned slot)
map < string , vector < string > > ptn_map ;
vector < string > ptn_vec ;
const char ptn_list [ ] [ MAX_GPT_NAME_SIZE ] = { AB_PTN_LIST } ;
struct gpt_disk disk = { 0 } ;
uint32_t i ;
int rc = - 1 ;
map < string , vector < string > > : : iterator map_iter ;
@ -607,13 +569,13 @@ int set_active_boot_slot(unsigned slot)
if ( boot_control_check_slot_sanity ( slot ) ) {
fprintf ( stderr , " %s: Bad arguments \n " , __func__ ) ;
goto error ;
goto out ;
}
ismmc = gpt_utils_is_partition_backed_by_emmc ( PTN_XBL AB_SLOT_A_SUFFIX ) ;
if ( ! ismmc & & ufs_bsg_dev_open ( ) < 0 ) {
goto error ;
goto out ;
}
// The partition list just contains prefixes(without the _a/_b) of the
@ -629,6 +591,7 @@ int set_active_boot_slot(unsigned slot)
cur_ptn . append ( AB_SLOT_A_SUFFIX ) ;
ptn_vec . push_back ( cur_ptn ) ;
}
// The partition map gives us info in the following format:
// [path_to_block_device_1]--><partitions on device 1>
// [path_to_block_device_2]--><partitions on device 2>
@ -638,19 +601,14 @@ int set_active_boot_slot(unsigned slot)
// [/dev/block/sdb]---><system, boot, rpm, tz,....>
if ( gpt_utils_get_partition_map ( ptn_vec , ptn_map ) ) {
fprintf ( stderr , " %s: Failed to get partition map \n " , __func__ ) ;
goto error ;
goto out ;
}
for ( map_iter = ptn_map . begin ( ) ; map_iter ! = ptn_map . end ( ) ;
map_iter + + ) {
for ( map_iter = ptn_map . begin ( ) ; map_iter ! = ptn_map . end ( ) ; map_iter + + ) {
if ( map_iter - > second . size ( ) < 1 )
continue ;
if ( boot_ctl_set_active_slot_for_partitions ( map_iter - > second ,
slot ) ) {
fprintf ( stderr ,
" %s: Failed to set active slot for partitions \n " ,
__func__ ) ;
;
goto error ;
if ( boot_ctl_set_active_slot_for_partitions ( & disk , map_iter - > second , slot ) ) {
fprintf ( stderr , " %s: Failed to set active slot for partitions \n " , __func__ ) ;
goto out ;
}
}
@ -658,68 +616,59 @@ int set_active_boot_slot(unsigned slot)
if ( ismmc )
return 0 ;
if ( ! strncmp ( slot_suffix_arr [ slot ] , AB_SLOT_A_SUFFIX ,
strlen ( AB_SLOT_A_SUFFIX ) ) ) {
if ( slot = = 0 ) {
// Set xbl_a as the boot lun
rc = gpt_utils_set_xbl_boot_partition ( NORMAL_BOOT ) ;
} else if ( ! strncmp ( slot_suffix_arr [ slot ] , AB_SLOT_B_SUFFIX ,
strlen ( AB_SLOT_B_SUFFIX ) ) ) {
} else if ( slot = = 1 ) {
// Set xbl_b as the boot lun
rc = gpt_utils_set_xbl_boot_partition ( BACKUP_BOOT ) ;
} else {
// Something has gone terribly terribly wrong
fprintf ( stderr , " %s: Unknown slot suffix! \n " , __func__ ) ;
goto error ;
goto out ;
}
if ( rc ) {
fprintf ( stderr ,
" %s: Failed to switch xbl boot partition \n " ,
__func__ ) ;
goto error ;
fprintf ( stderr , " %s: Failed to switch xbl boot partition \n " , __func__ ) ;
goto out ;
}
gpt_disk_free ( & disk ) ;
return 0 ;
error :
out :
gpt_disk_free ( & disk ) ;
return - 1 ;
}
int set_slot_as_unbootable ( unsigned slot )
{
if ( boot_control_check_slot_sanity ( slot ) ! = 0 ) {
fprintf ( stderr , " %s: Argument check failed \n " , __func__ ) ;
goto error ;
}
if ( update_slot_attribute ( slot_suffix_arr [ slot ] , ATTR_UNBOOTABLE ) ) {
goto error ;
}
return 0 ;
error :
fprintf ( stderr , " %s: Failed to mark slot unbootable \n " , __func__ ) ;
struct gpt_disk disk = { 0 } ;
int ret ;
if ( boot_control_check_slot_sanity ( slot ) ! = 0 )
return - 1 ;
ret = update_slot_attribute ( & disk , slot_suffix_arr [ slot ] , ATTR_UNBOOTABLE ) ;
gpt_disk_free ( & disk ) ;
return ret ;
}
int is_slot_marked_successful ( unsigned slot )
{
int attr = 0 ;
char bootPartition [ MAX_GPT_NAME_SIZE + 1 ] = { 0 } ;
int ret ;
struct gpt_disk disk = { 0 } ;
if ( boot_control_check_slot_sanity ( slot ) ! = 0 ) {
fprintf ( stderr , " %s: Argument check failed \n " , __func__ ) ;
goto error ;
}
snprintf ( bootPartition , sizeof ( bootPartition ) - 1 , " boot%s " ,
slot_suffix_arr [ slot ] ) ;
attr = get_partition_attribute ( bootPartition , ATTR_BOOT_SUCCESSFUL ) ;
LOGD ( " %s: slot = %d, attr = 0x%x \n " , __func__ , slot , attr ) ;
if ( attr > = 0 )
return attr ;
error :
if ( boot_control_check_slot_sanity ( slot ) ! = 0 )
return - 1 ;
ret = get_boot_attr ( & disk , slot , ATTR_BOOT_SUCCESSFUL ) ;
gpt_disk_free ( & disk ) ;
return ret ;
}
const struct boot_control_module bootctl = {
. getCurrentSlot = get_current_slot ,
. getCurrentSlot = get_current_slot_from_kernel_cmdline ,
. markBootSuccessful = mark_boot_successful ,
. setActiveBootSlot = set_active_boot_slot ,
. setSlotAsUnbootable = set_slot_as_unbootable ,