rework, fixup, cleanup

Allocate gpt_disk on stack, allocate when needed, rather than multiple
times for every partition.

Huge code cleanup, rerun clang-format, etc

Many changes here inspired by Eric's earlier work.
main
Caleb Connolly 11 months ago
parent 7f852512b6
commit 04f4ac81ea
No known key found for this signature in database
GPG Key ID: 0583312B195F64B6
  1. 10
      .clang-format
  2. 687
      bootctrl_impl.cpp
  3. 601
      gpt-utils.cpp
  4. 7
      gpt-utils.h
  5. 8
      meson.build
  6. 11
      qbootctl.cpp
  7. 2
      utils.h

@ -54,7 +54,7 @@ BreakConstructorInitializersBeforeComma: false
#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
ColumnLimit: 80
ColumnLimit: 100
CommentPragmas: '^ IWYU pragma:'
#CompactNamespaces: false # Unknown to clang-format-4.0
ConstructorInitializerAllOnOneLineOrOnePerLine: false
@ -89,16 +89,16 @@ ObjCSpaceBeforeProtocolList: true
# Taken from git's rules
#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0
PenaltyBreakBeforeFirstCallParameter: 30
PenaltyBreakBeforeFirstCallParameter: 50
PenaltyBreakComment: 10
PenaltyBreakFirstLessLess: 0
PenaltyBreakString: 10
PenaltyExcessCharacter: 100
PenaltyExcessCharacter: 30
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: false
SortIncludes: false
SortIncludes: true
#SortUsingDeclarations: false # Unknown to clang-format-4.0
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
@ -114,7 +114,7 @@ SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp03
Standard: Cpp11
TabWidth: 8
UseTab: Always
...

@ -13,28 +13,28 @@
* 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/>.
* 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"
@ -47,15 +47,14 @@
#define SLOT_ACTIVE 1
#define SLOT_INACTIVE 2
#define UPDATE_SLOT(pentry, guid, slot_state) \
({ \
memcpy(pentry, guid, TYPE_GUID_SIZE); \
if (slot_state == SLOT_ACTIVE) \
*(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); \
#define UPDATE_SLOT(pentry, guid, slot_state) \
({ \
memcpy(pentry, guid, TYPE_GUID_SIZE); \
if (slot_state == SLOT_ACTIVE) \
*(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); \
})
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);
@ -99,133 +97,137 @@ error:
strcpy(buf, def);
}
//Get the value of one of the attribute fields for a partition.
static int get_partition_attribute(char *partname,
// Get the value of one of the attribute fields for a partition.
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)
// Set a particular attribute for all the partitions in a
// slot
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);
// 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);
if (stat(buf, &st) < 0) {
//partition does not have _a version
// 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
// 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,106 +243,75 @@ 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;
}
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;
return -1;
}
gpt_disk_free(disk);
disk = NULL;
}
if (gpt_disk_commit(disk)) {
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);
return 0;
}
static unsigned int get_current_slot()
{
uint32_t num_slots = 0;
char bootSlotProp[MAX_CMDLINE_SIZE] = { '\0' };
unsigned i = 0;
num_slots = get_number_slots();
if (num_slots <= 1) {
//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;
}
//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]))) {
//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;
return slot_count;
}
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");
fprintf(stderr, "Invalid slot number %u\n", slot);
return -1;
}
return 0;
}
int get_boot_attr(unsigned slot, enum part_attr_type attr)
int get_boot_attr(struct gpt_disk *disk, unsigned slot, enum part_attr_type attr)
{
char bootPartition[MAX_GPT_NAME_SIZE + 1] = { 0 };
@ -348,16 +319,50 @@ int get_boot_attr(unsigned slot, enum part_attr_type attr)
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);
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' };
unsigned i = 0;
num_slots = get_number_slots();
if (num_slots <= 1) {
// 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__);
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] != nullptr; i++) {
if (!strncmp(bootSlotProp, slot_suffix_arr[i], strlen(slot_suffix_arr[i]))) {
// printf("%s current_slot = %d\n", __func__, i);
return i;
}
}
// 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;
}
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,236 +413,186 @@ 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,
// 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(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;
//Pointer to partition entry of current 'B' partition
uint8_t *pentryB = NULL;
uint8_t *pentryB_bak = NULL;
// Pointer to the partition entry of current 'A' partition
uint8_t *pentryA = nullptr;
uint8_t *pentryA_bak = nullptr;
// Pointer to partition entry of current 'B' partition
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++) {
//Chop off the slot suffix from the partition name to
//make the string easier to work with.
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);
// 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);
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);
//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;
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 (!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.
// Get partition entry for slot A & B from the primary
// and backup tables.
pentryA = gpt_disk_get_pentry(disk, slotA, PRIMARY_GPT);
pentryA_bak = gpt_disk_get_pentry(disk, slotA, SECONDARY_GPT);
pentryB = gpt_disk_get_pentry(disk, slotB, PRIMARY_GPT);
pentryB_bak = gpt_disk_get_pentry(disk, slotB, SECONDARY_GPT);
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;
// 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());
return -1;
}
LOGD("\tAB attr (A): 0x%x (backup: 0x%x)\n",
*(uint16_t *)(pentryA + AB_FLAG_OFFSET),
LOGD("\tAB attr (A): 0x%x (backup: 0x%x)\n", *(uint16_t *)(pentryA + AB_FLAG_OFFSET),
*(uint16_t *)(pentryA_bak + AB_FLAG_OFFSET));
LOGD("\tAB attr (B): 0x%x (backup: 0x%x)\n",
*(uint16_t *)(pentryB + AB_FLAG_OFFSET),
LOGD("\tAB 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) {
//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) {
//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);
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(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);
} 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))) {
//Mark A as active in primary table
UPDATE_SLOT(pentryA, active_guid, SLOT_ACTIVE);
//Mark A as active in backup table
UPDATE_SLOT(pentryA_bak, active_guid, SLOT_ACTIVE);
//Mark B as inactive in primary table
UPDATE_SLOT(pentryB, inactive_guid, SLOT_INACTIVE);
//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;
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, a_state);
// Mark A as active in backup table
UPDATE_SLOT(pentryA_bak, active_guid, a_state);
// Mark B as inactive in primary table
UPDATE_SLOT(pentryB, inactive_guid, b_state);
// Mark B as inactive in backup table
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);
// write updated content to disk
if (gpt_disk_commit(disk)) {
fprintf(stderr, "Failed to commit disk entry");
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.
// 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;
}
int set_active_boot_slot(unsigned slot)
{
map<string, vector<string> > ptn_map;
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;
map<string, vector<string>>::iterator map_iter;
bool ismmc;
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
//partitions that support A/B. In order to get the layout we need the
//actual names. To do this we append the slot suffix to every member
//in the list.
// The partition list just contains prefixes(without the _a/_b) of the
// partitions that support A/B. In order to get the layout we need the
// actual names. To do this we append the slot suffix to every member
// in the list.
for (i = 0; i < ARRAY_SIZE(ptn_list); i++) {
//XBL is handled differrently for ufs devices so ignore it
// XBL is handled differrently for ufs devices so ignore it
if (!ismmc && !strncmp(ptn_list[i], PTN_XBL, strlen(PTN_XBL)))
continue;
//The partition list will be the list of _a partitions
// The partition list will be the list of _a partitions
string cur_ptn = ptn_list[i];
cur_ptn.append(AB_SLOT_A_SUFFIX);
ptn_vec.push_back(cur_ptn);
}
//The partition map gives us info in the following format:
// 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))) {
//Set xbl_a as the boot lun
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))) {
//Set xbl_b as the boot lun
} 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
// 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__);
return -1;
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:
return -1;
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,

@ -30,27 +30,28 @@
#define _LARGEFILE64_SOURCE /* enable lseek64() */
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <linux/fs.h>
#include <limits.h>
#include "assert.h"
#include <asm/byteorder.h>
#include <dirent.h>
#include <endian.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <asm/byteorder.h>
#include <map>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <string>
#include <endian.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <vector>
#include <zlib.h>
#include "utils.h"
#include "gpt-utils.h"
#include "utils.h"
/* list the names of the backed-up partitions to be swapped */
/* extension used for the backup partitions - tzbak, abootbak, etc. */
@ -61,16 +62,16 @@
#define XBL_AB_SECONDARY "/dev/disk/by-partlabel/xbl_b"
/* GPT defines */
#define MAX_LUNS 26
//Size of the buffer that needs to be passed to the UFS ioctl
// Size of the buffer that needs to be passed to the UFS ioctl
#define UFS_ATTR_DATA_SIZE 32
//This will allow us to get the root lun path from the path to the partition.
//i.e: from /dev/disk/sdaXXX get /dev/disk/sda. The assumption here is that
//the boot critical luns lie between sda to sdz which is acceptable because
//only user added external disks,etc would lie beyond that limit which do not
//contain partitions that interest us here.
// This will allow us to get the root lun path from the path to the partition.
// i.e: from /dev/disk/sdaXXX get /dev/disk/sda. The assumption here is that
// the boot critical luns lie between sda to sdz which is acceptable because
// only user added external disks,etc would lie beyond that limit which do not
// contain partitions that interest us here.
#define PATH_TRUNCATE_LOC (sizeof("/dev/sda") - 1)
//From /dev/disk/sda get just sda
// From /dev/disk/sda get just sda
#define LUN_NAME_START_LOC (sizeof("/dev/") - 1)
#define BOOT_LUN_A_ID 1
#define BOOT_LUN_B_ID 2
@ -78,26 +79,22 @@
* MACROS
******************************************************************************/
#define GET_4_BYTES(ptr) \
((uint32_t) * ((uint8_t *)(ptr)) | \
((uint32_t) * ((uint8_t *)(ptr) + 1) << 8) | \
((uint32_t) * ((uint8_t *)(ptr) + 2) << 16) | \
((uint32_t) * ((uint8_t *)(ptr) + 3) << 24))
#define GET_8_BYTES(ptr) \
((uint64_t) * ((uint8_t *)(ptr)) | \
((uint64_t) * ((uint8_t *)(ptr) + 1) << 8) | \
((uint64_t) * ((uint8_t *)(ptr) + 2) << 16) | \
((uint64_t) * ((uint8_t *)(ptr) + 3) << 24) | \
((uint64_t) * ((uint8_t *)(ptr) + 4) << 32) | \
((uint64_t) * ((uint8_t *)(ptr) + 5) << 40) | \
((uint64_t) * ((uint8_t *)(ptr) + 6) << 48) | \
((uint64_t) * ((uint8_t *)(ptr) + 7) << 56))
#define PUT_4_BYTES(ptr, y) \
*((uint8_t *)(ptr)) = (y)&0xff; \
*((uint8_t *)(ptr) + 1) = ((y) >> 8) & 0xff; \
*((uint8_t *)(ptr) + 2) = ((y) >> 16) & 0xff; \
#define GET_4_BYTES(ptr) \
((uint32_t) * ((uint8_t *)(ptr)) | ((uint32_t) * ((uint8_t *)(ptr) + 1) << 8) | \
((uint32_t) * ((uint8_t *)(ptr) + 2) << 16) | ((uint32_t) * ((uint8_t *)(ptr) + 3) << 24))
#define GET_8_BYTES(ptr) \
((uint64_t) * ((uint8_t *)(ptr)) | ((uint64_t) * ((uint8_t *)(ptr) + 1) << 8) | \
((uint64_t) * ((uint8_t *)(ptr) + 2) << 16) | \
((uint64_t) * ((uint8_t *)(ptr) + 3) << 24) | \
((uint64_t) * ((uint8_t *)(ptr) + 4) << 32) | \
((uint64_t) * ((uint8_t *)(ptr) + 5) << 40) | \
((uint64_t) * ((uint8_t *)(ptr) + 6) << 48) | ((uint64_t) * ((uint8_t *)(ptr) + 7) << 56))
#define PUT_4_BYTES(ptr, y) \
*((uint8_t *)(ptr)) = (y)&0xff; \
*((uint8_t *)(ptr) + 1) = ((y) >> 8) & 0xff; \
*((uint8_t *)(ptr) + 2) = ((y) >> 16) & 0xff; \
*((uint8_t *)(ptr) + 3) = ((y) >> 24) & 0xff;
/******************************************************************************
@ -105,8 +102,8 @@
******************************************************************************/
using namespace std;
enum gpt_state { GPT_OK = 0, GPT_BAD_SIGNATURE, GPT_BAD_CRC };
//List of LUN's containing boot critical images.
//Required in the case of UFS devices
// List of LUN's containing boot critical images.
// Required in the case of UFS devices
struct update_data {
char lun_list[MAX_LUNS][PATH_MAX];
uint32_t num_valid_entries;
@ -122,8 +119,7 @@ void DumpHex(const void *data, size_t size)
ascii[16] = '\0';
for (i = 0; i < size; ++i) {
printf("%02X ", ((unsigned char *)data)[i]);
if (((unsigned char *)data)[i] >= ' ' &&
((unsigned char *)data)[i] <= '~') {
if (((unsigned char *)data)[i] >= ' ' && ((unsigned char *)data)[i] <= '~') {
ascii[i % 16] = ((unsigned char *)data)[i];
} else {
ascii[i % 16] = '.';
@ -166,8 +162,8 @@ static int blk_rw(int fd, int rw, uint64_t offset, uint8_t *buf, unsigned len)
int r;
if (lseek64(fd, offset, SEEK_SET) < 0) {
fprintf(stderr, "block dev lseek64 %" PRIu64 " failed: %s\n",
offset, strerror(errno));
fprintf(stderr, "block dev lseek64 %" PRIu64 " failed: %s\n", offset,
strerror(errno));
return -1;
}
@ -177,14 +173,13 @@ static int blk_rw(int fd, int rw, uint64_t offset, uint8_t *buf, unsigned len)
r = read(fd, buf, len);
if (r < 0) {
fprintf(stderr, "block dev %s failed: %s\n",
rw ? "write" : "read\n", strerror(errno));
fprintf(stderr, "block dev %s failed: %s\n", rw ? "write" : "read\n",
strerror(errno));
} else {
if (rw) {
r = fsync(fd);
if (r < 0)
fprintf(stderr, "fsync failed: %s\n",
strerror(errno));
fprintf(stderr, "fsync failed: %s\n", strerror(errno));
} else {
r = 0;
}
@ -204,14 +199,12 @@ static int blk_rw(int fd, int rw, uint64_t offset, uint8_t *buf, unsigned len)
* \param [in] pentries_end Partition entries array end pointer
* \param [in] pentry_size Single partition entry size [bytes]
*
* \return First partition entry pointer that matches the name or NULL
* \return First partition entry pointer that matches the name or null
*
* ==========================================================================
*/
static uint8_t *gpt_pentry_seek(const char *ptn_name,
const uint8_t *pentries_start,
const uint8_t *pentries_end,
uint32_t pentry_size)
static uint8_t *gpt_pentry_seek(const char *ptn_name, const uint8_t *pentries_start,
const uint8_t *pentries_end, uint32_t pentry_size)
{
char *pentry_name;
unsigned len = strlen(ptn_name);
@ -225,26 +218,24 @@ static uint8_t *gpt_pentry_seek(const char *ptn_name,
for (i = 0; i < sizeof(name8); i++)
name8[i] = pentry_name[i * 2];
if (!strncmp(ptn_name, name8, len))
if (name8[len] == 0 ||
!strcmp(&name8[len], BAK_PTN_NAME_EXT))
return (uint8_t *)(pentry_name -
PARTITION_NAME_OFFSET);
if (name8[len] == 0 || !strcmp(&name8[len], BAK_PTN_NAME_EXT))
return (uint8_t *)(pentry_name - PARTITION_NAME_OFFSET);
}
return NULL;
return nullptr;
}
// Defined in ufs-bsg.cpp
int32_t set_boot_lun(uint8_t lun_id);
//Swtich betwieen using either the primary or the backup
//boot LUN for boot. This is required since UFS boot partitions
//cannot have a backup GPT which is what we use for failsafe
//updates of the other 'critical' partitions. This function will
//not be invoked for emmc targets and on UFS targets is only required
//to be invoked for XBL.
// Swtich betwieen using either the primary or the backup
// boot LUN for boot. This is required since UFS boot partitions
// cannot have a backup GPT which is what we use for failsafe
// updates of the other 'critical' partitions. This function will
// not be invoked for emmc targets and on UFS targets is only required
// to be invoked for XBL.
//
//The algorithm to do this is as follows:
// The algorithm to do this is as follows:
//- Find the real block device(eg: /dev/disk/sdb) that corresponds
// to the /dev/disk/bootdevice/by-name/xbl(bak) symlink
//
@ -253,12 +244,12 @@ int32_t set_boot_lun(uint8_t lun_id);
// it by checking the file /sys/block/sdb/device/scsi_generic/sgY
//
//- Once we locate sgY we call the query ioctl on /dev/sgy to switch
//the boot lun to either LUNA or LUNB
// the boot lun to either LUNA or LUNB
int gpt_utils_set_xbl_boot_partition(enum boot_chain chain)
{
struct stat st;
uint8_t boot_lun_id = 0;
const char *boot_dev = NULL;
const char *boot_dev = nullptr;
(void)st;
(void)boot_dev;
@ -270,8 +261,7 @@ int gpt_utils_set_xbl_boot_partition(enum boot_chain chain)
else if (!stat(XBL_AB_SECONDARY, &st))
boot_dev = XBL_AB_SECONDARY;
else {
fprintf(stderr, "%s: Failed to locate secondary xbl\n",
__func__);
fprintf(stderr, "%s: Failed to locate secondary xbl\n", __func__);
goto error;
}
} else if (chain == NORMAL_BOOT) {
@ -281,20 +271,19 @@ int gpt_utils_set_xbl_boot_partition(enum boot_chain chain)
else if (!stat(XBL_AB_PRIMARY, &st))
boot_dev = XBL_AB_PRIMARY;
else {
fprintf(stderr, "%s: Failed to locate primary xbl\n",
__func__);
fprintf(stderr, "%s: Failed to locate primary xbl\n", __func__);
goto error;
}
} else {
fprintf(stderr, "%s: Invalid boot chain id\n", __func__);
goto error;
}
//We need either both xbl and xblbak or both xbl_a and xbl_b to exist at
//the same time. If not the current configuration is invalid.
// We need either both xbl and xblbak or both xbl_a and xbl_b to exist at
// the same time. If not the current configuration is invalid.
if ((stat(XBL_PRIMARY, &st) || stat(XBL_BACKUP, &st)) &&
(stat(XBL_AB_PRIMARY, &st) || stat(XBL_AB_SECONDARY, &st))) {
fprintf(stderr, "%s:primary/secondary XBL prt not found(%s)\n",
__func__, strerror(errno));
fprintf(stderr, "%s:primary/secondary XBL prt not found(%s)\n", __func__,
strerror(errno));
goto error;
}
LOGD("%s: setting %s lun as boot lun\n", __func__, boot_dev);
@ -307,30 +296,25 @@ error:
return -1;
}
//Given a parttion name(eg: rpm) get the path to the block device that
//represents the GPT disk the partition resides on. In the case of emmc it
//would be the default emmc dev(/dev/mmcblk0). In the case of UFS we look
//through the /dev/disk/bootdevice/by-name/ tree for partname, and resolve
//the path to the LUN from there.
static int get_dev_path_from_partition_name(const char *partname, char *buf,
size_t buflen)
// Given a parttion name(eg: rpm) get the path to the block device that
// represents the GPT disk the partition resides on. In the case of emmc it
// would be the default emmc dev(/dev/mmcblk0). In the case of UFS we look
// through the /dev/disk/bootdevice/by-name/ tree for partname, and resolve
// the path to the LUN from there.
static int get_dev_path_from_partition_name(const char *partname, char *buf, size_t buflen)
{
struct stat st;
char path[PATH_MAX] = { 0 };
int i;
(void)st;
if (!partname || !buf || buflen < ((PATH_TRUNCATE_LOC) + 1)) {
fprintf(stderr, "%s: Invalid argument\n", __func__);
return -1;
}
//Need to find the lun that holds partition partname
// Need to find the lun that holds partition partname
snprintf(path, sizeof(path), "%s/%s", BOOT_DEV_DIR, partname);
// if (rc = stat(path, &st)) {
// LOGD("stat failed: errno=%d\n", errno);
// goto error;
// }
buf = realpath(path, buf);
if (!buf) {
return -1;
@ -344,28 +328,30 @@ static int get_dev_path_from_partition_name(const char *partname, char *buf,
buf[i] = 0;
}
return 0;
}
int gpt_utils_get_partition_map(vector<string> &ptn_list,
map<string, vector<string> > &partition_map)
int gpt_utils_get_partition_map(vector<string> &ptn_list, map<string, vector<string>> &partition_map)
{
char devpath[PATH_MAX] = { '\0' };
map<string, vector<string> >::iterator it;
map<string, vector<string>>::iterator it;
if (ptn_list.size() < 1) {
fprintf(stderr, "%s: Invalid ptn list\n", __func__);
return -1;
}
//Go through the passed in list
// Go through the passed in list
for (uint32_t i = 0; i < ptn_list.size(); i++) {
//Key in the map is the path to the device that holds the
//partition
if (get_dev_path_from_partition_name(
ptn_list[i].c_str(), devpath, sizeof(devpath))) {
//Not necessarily an error. The partition may just
//not be present.
// Key in the map is the path to the device that holds the
// partition
if (get_dev_path_from_partition_name(ptn_list[i].c_str(), devpath, sizeof(devpath))) {
// Not necessarily an error. The partition may just
// not be present.
continue;
}
string path = devpath;
it = partition_map.find(path);
if (it != partition_map.end()) {
@ -373,144 +359,153 @@ int gpt_utils_get_partition_map(vector<string> &ptn_list,
} else {
vector<string> str_vec;
str_vec.push_back(ptn_list[i]);
partition_map.insert(
pair<string, vector<string> >(path, str_vec));
partition_map.insert(pair<string, vector<string>>(path, str_vec));
}
memset(devpath, '\0', sizeof(devpath));
}
return 0;
}
//Get the block size of the disk represented by decsriptor fd
// Get the block size of the disk represented by decsriptor fd
static uint32_t gpt_get_block_size(int fd)
{
uint32_t block_size = 0;
if (fd < 0) {
fprintf(stderr, "%s: invalid descriptor\n", __func__);
goto error;
}
if (ioctl(fd, BLKSSZGET, &block_size) != 0) {
fprintf(stderr, "%s: Failed to get GPT dev block size : %s\n",
__func__, strerror(errno));
fprintf(stderr, "%s: Failed to get GPT dev block size : %s\n", __func__,
strerror(errno));
goto error;
}
return block_size;
error:
return 0;
}
//Write the GPT header present in the passed in buffer back to the
//disk represented by fd
static int gpt_set_header(uint8_t *gpt_header, int fd,
enum gpt_instance instance)
// Write the GPT header present in the passed in buffer back to the
// disk represented by fd
static int gpt_set_header(uint8_t *gpt_header, int fd, enum gpt_instance instance)
{
uint32_t block_size = 0;
off_t gpt_header_offset = 0;
if (!gpt_header || fd < 0) {
fprintf(stderr, "%s: Invalid arguments\n", __func__);
goto error;
}
block_size = gpt_get_block_size(fd);
LOGD("%s: Block size is : %d\n", __func__, block_size);
if (block_size == 0) {
fprintf(stderr, "%s: Failed to get block size\n", __func__);
goto error;
}
if (instance == PRIMARY_GPT)
gpt_header_offset = block_size;
else
gpt_header_offset = lseek64(fd, 0, SEEK_END) - block_size;
if (gpt_header_offset <= 0) {
fprintf(stderr, "%s: Failed to get gpt header offset\n",
__func__);
fprintf(stderr, "%s: Failed to get gpt header offset\n", __func__);
goto error;
}
LOGD("%s: Writing back header to offset %ld\n", __func__,
gpt_header_offset);
LOGD("%s: Writing back header to offset %ld\n", __func__, gpt_header_offset);
if (blk_rw(fd, 1, gpt_header_offset, gpt_header, block_size)) {
fprintf(stderr, "%s: Failed to write back GPT header\n",
__func__);
fprintf(stderr, "%s: Failed to write back GPT header\n", __func__);
goto error;
}
return 0;
error:
return -1;
}
//Read out the GPT header for the disk that contains the partition partname
static uint8_t *gpt_get_header(const char *partname, enum gpt_instance instance)
// Read out the GPT headers for the disk that contains the partition partname
static int gpt_get_headers(const char *partname, uint8_t **primary, uint8_t **backup)
{
uint8_t *hdr = NULL;
uint8_t *hdr = nullptr;
char devpath[PATH_MAX] = { 0 };
off_t hdr_offset = 0;
uint32_t block_size = 0;
int instance;
int fd = -1;
if (!partname) {
fprintf(stderr, "%s: Invalid partition name\n", __func__);
goto error;
}
if (get_dev_path_from_partition_name(partname, devpath,
sizeof(devpath)) != 0) {
fprintf(stderr, "%s: Failed to resolve path for %s\n", __func__,
partname);
if (get_dev_path_from_partition_name(partname, devpath, sizeof(devpath)) != 0) {
fprintf(stderr, "%s: Failed to resolve path for %s\n", __func__, partname);
goto error;
}
fd = open(devpath, O_RDWR);
if (fd < 0) {
fprintf(stderr, "%s: Failed to open %s : %s\n", __func__,
devpath, strerror(errno));
goto error;
fprintf(stderr, "%s: Failed to open %s : %s\n", __func__, devpath, strerror(errno));
return -1;
}
block_size = gpt_get_block_size(fd);
if (block_size == 0) {
fprintf(stderr, "%s: Failed to get gpt block size for %s\n",
__func__, partname);
fprintf(stderr, "%s: Failed to get gpt block size for %s\n", __func__, partname);
goto error;
}
hdr = (uint8_t *)calloc(block_size, 1);
if (!hdr) {
fprintf(stderr,
"%s: Failed to allocate memory for gpt header\n",
__func__);
}
if (instance == PRIMARY_GPT)
hdr_offset = block_size;
else {
hdr_offset = lseek64(fd, 0, SEEK_END) - block_size;
}
if (hdr_offset < 0) {
fprintf(stderr, "%s: Failed to get gpt header offset\n",
__func__);
goto error;
}
if (blk_rw(fd, 0, hdr_offset, hdr, block_size)) {
fprintf(stderr, "%s: Failed to read GPT header from device\n",
__func__);
goto error;
for (instance = PRIMARY_GPT; instance <= SECONDARY_GPT; instance++) {
hdr = (uint8_t *)calloc(block_size, 1);
if (!hdr) {
fprintf(stderr, "%s: Failed to allocate memory for gpt header\n", __func__);
}
if (instance == PRIMARY_GPT)
hdr_offset = block_size;
else {
hdr_offset = lseek64(fd, 0, SEEK_END) - block_size;
}
if (hdr_offset < 0) {
fprintf(stderr, "%s: Failed to get gpt header offset\n", __func__);
goto error;
}
if (blk_rw(fd, 0, hdr_offset, hdr, block_size)) {
fprintf(stderr, "%s: Failed to read GPT header from device\n", __func__);
goto error;
}
if (instance == PRIMARY_GPT)
*primary = hdr;
else
*backup = hdr;
}
//DumpHex(hdr, block_size);
close(fd);
return hdr;
return 0;
error:
if (fd >= 0)
close(fd);
close(fd);
if (hdr)
free(hdr);
return NULL;
return -1;
}
//Returns the partition entry array based on the
//passed in buffer which contains the gpt header.
//The fd here is the descriptor for the 'disk' which
//holds the partition
// Returns the partition entry array based on the
// passed in buffer which contains the gpt header.
// The fd here is the descriptor for the 'disk' which
// holds the partition
static uint8_t *gpt_get_pentry_arr(uint8_t *hdr, int fd)
{
uint64_t pentries_start = 0;
uint32_t pentry_size = 0;
uint32_t block_size = 0;
uint32_t pentries_arr_size = 0;
uint8_t *pentry_arr = NULL;
uint8_t *pentry_arr = nullptr;
int rc = 0;
if (!hdr) {
fprintf(stderr, "%s: Invalid header\n", __func__);
@ -522,32 +517,27 @@ static uint8_t *gpt_get_pentry_arr(uint8_t *hdr, int fd)
}
block_size = gpt_get_block_size(fd);
if (!block_size) {
fprintf(stderr, "%s: Failed to get gpt block size for\n",
__func__);
fprintf(stderr, "%s: Failed to get gpt block size for\n", __func__);
goto error;
}
pentries_start = GET_8_BYTES(hdr + PENTRIES_OFFSET) * block_size;
pentry_size = GET_4_BYTES(hdr + PENTRY_SIZE_OFFSET);
pentries_arr_size =
GET_4_BYTES(hdr + PARTITION_COUNT_OFFSET) * pentry_size;
pentries_arr_size = GET_4_BYTES(hdr + PARTITION_COUNT_OFFSET) * pentry_size;
pentry_arr = (uint8_t *)calloc(1, pentries_arr_size);
if (!pentry_arr) {
fprintf(stderr,
"%s: Failed to allocate memory for partition array\n",
__func__);
fprintf(stderr, "%s: Failed to allocate memory for partition array\n", __func__);
goto error;
}
rc = blk_rw(fd, 0, pentries_start, pentry_arr, pentries_arr_size);
if (rc) {
fprintf(stderr, "%s: Failed to read partition entry array\n",
__func__);
fprintf(stderr, "%s: Failed to read partition entry array\n", __func__);
goto error;
}
return pentry_arr;
error:
if (pentry_arr)
free(pentry_arr);
return NULL;
return nullptr;
}
static int gpt_set_pentry_arr(uint8_t *hdr, int fd, uint8_t *arr)
@ -563,23 +553,19 @@ static int gpt_set_pentry_arr(uint8_t *hdr, int fd, uint8_t *arr)
}
block_size = gpt_get_block_size(fd);
if (!block_size) {
fprintf(stderr, "%s: Failed to get gpt block size for\n",
__func__);
fprintf(stderr, "%s: Failed to get gpt block size for\n", __func__);
goto error;
}
LOGD("%s : Block size is %d\n", __func__, block_size);
pentries_start = GET_8_BYTES(hdr + PENTRIES_OFFSET) * block_size;
pentry_size = GET_4_BYTES(hdr + PENTRY_SIZE_OFFSET);
pentries_arr_size =
GET_4_BYTES(hdr + PARTITION_COUNT_OFFSET) * pentry_size;
LOGD("%s: Writing partition entry array of size %d to offset %" PRIu64
"\n",
__func__, pentries_arr_size, pentries_start);
pentries_arr_size = GET_4_BYTES(hdr + PARTITION_COUNT_OFFSET) * pentry_size;
LOGD("%s: Writing partition entry array of size %d to offset %" PRIu64 "\n", __func__,
pentries_arr_size, pentries_start);
LOGD("pentries_start: %lu\n", pentries_start);
rc = blk_rw(fd, 1, pentries_start, arr, pentries_arr_size);
if (rc) {
fprintf(stderr, "%s: Failed to read partition entry array\n",
__func__);
fprintf(stderr, "%s: Failed to read partition entry array\n", __func__);
goto error;
}
return 0;
@ -587,100 +573,134 @@ error:
return -1;
}
//Allocate a handle used by calls to the "gpt_disk" api's
struct gpt_disk *gpt_disk_alloc()
{
struct gpt_disk *disk;
disk = (struct gpt_disk *)malloc(sizeof(struct gpt_disk));
if (!disk) {
fprintf(stderr, "%s: Failed to allocate memory\n", __func__);
goto end;
}
memset(disk, 0, sizeof(struct gpt_disk));
end:
return disk;
}
//Free previously allocated/initialized handle
/*
* Free previously allocated/initialized handle
* This function is always safe and must be called
* before discarding the handle.
* it is called automatically by gpt_disk_get_disk_info()
*/
void gpt_disk_free(struct gpt_disk *disk)
{
if (!disk)
return;
if (disk->hdr)
if (disk->hdr) {
free(disk->hdr);
if (disk->hdr_bak)
disk->hdr = nullptr;
}
if (disk->hdr_bak) {
free(disk->hdr_bak);
if (disk->pentry_arr)
disk->hdr_bak = nullptr;
}
if (disk->pentry_arr) {
free(disk->pentry_arr);
if (disk->pentry_arr_bak)
disk->pentry_arr = nullptr;
}
if (disk->pentry_arr_bak) {
free(disk->pentry_arr_bak);
free(disk);
disk->pentry_arr_bak = nullptr;
}
disk->is_initialized = 0;
return;
}
//fills up the passed in gpt_disk struct with information about the
//disk represented by path dev. Returns 0 on success and -1 on error.
int gpt_disk_get_disk_info(const char *dev, struct gpt_disk *dsk)
bool gpt_disk_is_valid(struct gpt_disk *disk)
{
return disk->is_initialized == GPT_DISK_INIT_MAGIC;
}
/*
* Check if a partition by-path is for the disk we have info for
* and populate the blockdev path.
* e.g. for /dev/disk/by-partlabel/system_a blockdev would be /dev/sda
*/
bool partition_is_for_disk(const char *part, struct gpt_disk *disk, char *blockdev, int blockdev_len)
{
int ret;
ret = get_dev_path_from_partition_name(part, blockdev, blockdev_len);
if (ret) {
fprintf(stderr, "%s: Failed to resolve path for %s\n", __func__, part);
return false;
}
if (!strcmp(blockdev, disk->devpath)) {
return true;
}
return false;
}
/*
* fills up the passed in gpt_disk struct with information about the
* disk represented by path dev. Returns 0 on success and -1 on error.
*/
int gpt_disk_get_disk_info(const char *dev, struct gpt_disk *disk)
{
struct gpt_disk *disk = NULL;
int fd = -1;
uint32_t gpt_header_size = 0;
char devpath[PATH_MAX] = { 0 };
if (!dsk || !dev) {
if (!disk || !dev) {
fprintf(stderr, "%s: Invalid arguments\n", __func__);
goto error;
}
disk = dsk;
disk->hdr = gpt_get_header(dev, PRIMARY_GPT);
if (!disk->hdr) {
fprintf(stderr, "%s: Failed to get primary header\n", __func__);
if (partition_is_for_disk(dev, disk, devpath, sizeof(devpath))) {
return 0;
}
if (disk->is_initialized == GPT_DISK_INIT_MAGIC) {
// We already have a valid disk handle. Free it.
LOGD("%s: Freeing disk handle for %s... -> %s\n", __func__, disk->devpath, devpath);
gpt_disk_free(disk);
}
// devpath popualted by partition_is_for_disk
strncpy(disk->devpath, devpath, sizeof(disk->devpath));
if (gpt_get_headers(dev, &disk->hdr, &disk->hdr_bak)) {
fprintf(stderr, "%s: Failed to get GPT headers\n", __func__);
goto error;
}
assert(disk->hdr != nullptr);
assert(disk->hdr_bak != nullptr);
gpt_header_size = GET_4_BYTES(disk->hdr + HEADER_SIZE_OFFSET);
// FIXME: pointer offsets crc bleh
disk->hdr_crc = crc32(0, disk->hdr, gpt_header_size);
disk->hdr_bak = gpt_get_header(dev, SECONDARY_GPT);
if (!disk->hdr_bak) {
fprintf(stderr, "%s: Failed to get backup header\n", __func__);
goto error;
}
disk->hdr_bak_crc = crc32(0, disk->hdr_bak, gpt_header_size);
//Descriptor for the block device. We will use this for further
//modifications to the partition table
if (get_dev_path_from_partition_name(dev, disk->devpath,
sizeof(disk->devpath)) != 0) {
fprintf(stderr, "%s: Failed to resolve path for %s\n", __func__,
dev);
goto error;
}
fd = open(disk->devpath, O_RDWR);
if (fd < 0) {
fprintf(stderr, "%s: Failed to open %s: %s\n", __func__,
disk->devpath, strerror(errno));
fprintf(stderr, "%s: Failed to open %s: %s\n", __func__, disk->devpath,
strerror(errno));
goto error;
}
assert(disk->pentry_arr == nullptr);
disk->pentry_arr = gpt_get_pentry_arr(disk->hdr, fd);
if (!disk->pentry_arr) {
fprintf(stderr, "%s: Failed to obtain partition entry array\n",
__func__);
fprintf(stderr, "%s: Failed to obtain partition entry array\n", __func__);
goto error;
}
assert(disk->pentry_arr_bak == nullptr);
disk->pentry_arr_bak = gpt_get_pentry_arr(disk->hdr_bak, fd);
if (!disk->pentry_arr_bak) {
fprintf(stderr,
"%s: Failed to obtain backup partition entry array\n",
__func__);
fprintf(stderr, "%s: Failed to obtain backup partition entry array\n", __func__);
goto error;
}
disk->pentry_size = GET_4_BYTES(disk->hdr + PENTRY_SIZE_OFFSET);
disk->pentry_arr_size =
GET_4_BYTES(disk->hdr + PARTITION_COUNT_OFFSET) *
disk->pentry_size;
disk->pentry_arr_size = GET_4_BYTES(disk->hdr + PARTITION_COUNT_OFFSET) * disk->pentry_size;
disk->pentry_arr_crc = GET_4_BYTES(disk->hdr + PARTITION_CRC_OFFSET);
disk->pentry_arr_bak_crc =
GET_4_BYTES(disk->hdr_bak + PARTITION_CRC_OFFSET);
disk->pentry_arr_bak_crc = GET_4_BYTES(disk->hdr_bak + PARTITION_CRC_OFFSET);
disk->block_size = gpt_get_block_size(fd);
close(fd);
disk->is_initialized = GPT_DISK_INIT_MAGIC;
@ -691,49 +711,54 @@ error:
return -1;
}
//Get pointer to partition entry from a allocated gpt_disk structure
uint8_t *gpt_disk_get_pentry(struct gpt_disk *disk, const char *partname,
enum gpt_instance instance)
// Get pointer to partition entry from a allocated gpt_disk structure
uint8_t *gpt_disk_get_pentry(struct gpt_disk *disk, const char *partname, enum gpt_instance instance)
{
uint8_t *ptn_arr = NULL;
uint8_t *ptn_arr = nullptr;
if (!disk || !partname || disk->is_initialized != GPT_DISK_INIT_MAGIC) {
fprintf(stderr, "%s: Invalid argument\n", __func__);
goto error;
fprintf(stderr, "%s: disk handle not initialised\n", __func__);
return nullptr;
}
ptn_arr = (instance == PRIMARY_GPT) ? disk->pentry_arr :
disk->pentry_arr_bak;
return (gpt_pentry_seek(partname, ptn_arr,
ptn_arr + disk->pentry_arr_size,
ptn_arr = (instance == PRIMARY_GPT) ? disk->pentry_arr : disk->pentry_arr_bak;
return (gpt_pentry_seek(partname, ptn_arr, ptn_arr + disk->pentry_arr_size,
disk->pentry_size));
error:
return NULL;
}
//Update CRC values for the various components of the gpt_disk
//structure. This function should be called after any of the fields
//have been updated before the structure contents are written back to
//disk.
int gpt_disk_update_crc(struct gpt_disk *disk)
// Update CRC values for the various components of the gpt_disk
// structure. This function should be called after any of the fields
// have been updated before the structure contents are written back to
// disk.
static int gpt_disk_update_crc(struct gpt_disk *disk)
{
uint32_t gpt_header_size = 0;
if (!disk || (disk->is_initialized != GPT_DISK_INIT_MAGIC)) {
fprintf(stderr, "%s: invalid argument\n", __func__);
goto error;
fprintf(stderr, "%s: disk not initialised!\n", __func__);
return -1;
}
//Recalculate the CRC of the primary partiton array
disk->pentry_arr_crc =
crc32(0, disk->pentry_arr, disk->pentry_arr_size);
//Recalculate the CRC of the backup partition array
disk->pentry_arr_bak_crc =
crc32(0, disk->pentry_arr_bak, disk->pentry_arr_size);
//Update the partition CRC value in the primary GPT header
#ifdef DEBUG
uint32_t old_crc = disk->pentry_arr_crc;
#endif
// Recalculate the CRC of the primary partiton array
disk->pentry_arr_crc = crc32(0, disk->pentry_arr, disk->pentry_arr_size);
LOGD("%s() disk %8s GPT hdr len %u crc: %08x -> %08x\n", __func__, disk->devpath,
disk->pentry_arr_size, old_crc, disk->pentry_arr_crc);
// DumpHex(disk->pentry_arr, disk->pentry_arr_size);
// Recalculate the CRC of the backup partition array
disk->pentry_arr_bak_crc = crc32(0, disk->pentry_arr_bak, disk->pentry_arr_size);
// Update the partition CRC value in the primary GPT header
PUT_4_BYTES(disk->hdr + PARTITION_CRC_OFFSET, disk->pentry_arr_crc);
//Update the partition CRC value in the backup GPT header
PUT_4_BYTES(disk->hdr_bak + PARTITION_CRC_OFFSET,
disk->pentry_arr_bak_crc);
//Update the CRC value of the primary header
// Update the partition CRC value in the backup GPT header
PUT_4_BYTES(disk->hdr_bak + PARTITION_CRC_OFFSET, disk->pentry_arr_bak_crc);
// Update the CRC value of the primary header
gpt_header_size = GET_4_BYTES(disk->hdr + HEADER_SIZE_OFFSET);
//Header CRC is calculated with its own CRC field set to 0
// Header CRC is calculated with its own CRC field set to 0
PUT_4_BYTES(disk->hdr + HEADER_CRC_OFFSET, 0);
PUT_4_BYTES(disk->hdr_bak + HEADER_CRC_OFFSET, 0);
disk->hdr_crc = crc32(0, disk->hdr, gpt_header_size);
@ -741,52 +766,55 @@ int gpt_disk_update_crc(struct gpt_disk *disk)
PUT_4_BYTES(disk->hdr + HEADER_CRC_OFFSET, disk->hdr_crc);
PUT_4_BYTES(disk->hdr_bak + HEADER_CRC_OFFSET, disk->hdr_bak_crc);
return 0;
error:
return -1;
}
//Write the contents of struct gpt_disk back to the actual disk
// Write the contents of struct gpt_disk back to the actual disk
int gpt_disk_commit(struct gpt_disk *disk)
{
int fd = -1;
if (!disk || (disk->is_initialized != GPT_DISK_INIT_MAGIC)) {
fprintf(stderr, "%s: Invalid args\n", __func__);
goto error;
}
if (gpt_disk_update_crc(disk)) {
fprintf(stderr, "%s: Failed to update CRC values\n", __func__);
goto error;
}
fd = open(disk->devpath, O_RDWR);
if (fd < 0) {
fprintf(stderr, "%s: Failed to open %s: %s\n", __func__,
disk->devpath, strerror(errno));
fprintf(stderr, "%s: Failed to open %s: %s\n", __func__, disk->devpath,
strerror(errno));
goto error;
}
LOGD("%s: Writing back primary GPT header\n", __func__);
//Write the primary header
// Write the primary header
if (gpt_set_header(disk->hdr, fd, PRIMARY_GPT) != 0) {
fprintf(stderr, "%s: Failed to update primary GPT header\n",
__func__);
fprintf(stderr, "%s: Failed to update primary GPT header\n", __func__);
goto error;
}
LOGD("%s: Writing back primary partition array\n", __func__);
//Write back the primary partition array
// Write back the primary partition array
if (gpt_set_pentry_arr(disk->hdr, fd, disk->pentry_arr)) {
fprintf(stderr,
"%s: Failed to write primary GPT partition arr\n",
__func__);
fprintf(stderr, "%s: Failed to write primary GPT partition arr\n", __func__);
goto error;
}
// Write the backup header
if (gpt_set_header(disk->hdr_bak, fd, SECONDARY_GPT) != 0) {
fprintf(stderr, "%s: Failed to update backup GPT header\n",
__func__);
fprintf(stderr, "%s: Failed to update backup GPT header\n", __func__);
goto error;
}
LOGD("%s: Writing back backup partition array\n", __func__);
// Write back the backup partition array
if (gpt_set_pentry_arr(disk->hdr_bak, fd, disk->pentry_arr_bak)) {
fprintf(stderr,
"%s: Failed to write backup GPT partition arr\n",
__func__);
fprintf(stderr, "%s: Failed to write backup GPT partition arr\n", __func__);
goto error;
}
fsync(fd);
@ -798,13 +826,14 @@ error:
return -1;
}
//Determine whether to handle the given partition as eMMC or UFS, using the
//name of the backing device.
// Determine whether to handle the given partition as eMMC or UFS, using the
// name of the backing device.
//
//Note: In undefined cases (i.e. /dev/mmcblk1 and unresolvable), this function
//will tend to prefer UFS behavior. If it incorrectly reports this, then the
//program should exit (e.g. by failing) before making any changes.
bool gpt_utils_is_partition_backed_by_emmc(const char *part) {
// Note: In undefined cases (i.e. /dev/mmcblk1 and unresolvable), this function
// will tend to prefer UFS behavior. If it incorrectly reports this, then the
// program should exit (e.g. by failing) before making any changes.
bool gpt_utils_is_partition_backed_by_emmc(const char *part)
{
char devpath[PATH_MAX] = { '\0' };
if (get_dev_path_from_partition_name(part, devpath, sizeof(devpath)))

@ -123,20 +123,19 @@ struct gpt_disk {
};
//GPT disk methods
struct gpt_disk *gpt_disk_alloc();
bool gpt_disk_is_valid(struct gpt_disk *disk);
//Free previously allocated gpt_disk struct
void gpt_disk_free(struct gpt_disk *disk);
//Get the details of the disk holding the partition whose name
//is passed in via dev
int gpt_disk_get_disk_info(const char *dev, struct gpt_disk *disk);
bool partition_is_for_disk(const char *part, struct gpt_disk *disk, char *blockdev, int blockdev_len);
//Get pointer to partition entry from a allocated gpt_disk structure
uint8_t *gpt_disk_get_pentry(struct gpt_disk *disk, const char *partname,
enum gpt_instance instance);
//Update the crc fields of the modified disk structure
int gpt_disk_update_crc(struct gpt_disk *disk);
//Write the contents of struct gpt_disk back to the actual disk
int gpt_disk_commit(struct gpt_disk *disk);

@ -1,9 +1,15 @@
project('qbootctl', 'cpp')
project('qbootctl', 'cpp', default_options : ['c_std=c11', 'cpp_std=c++17'])
cc = meson.get_compiler('cpp')
deps = [
dependency('zlib'),
]
if not cc.has_header('linux/bsg.h')
error('linux-headers not found')
endif
src = [
'qbootctl.cpp',
'bootctrl_impl.cpp',

@ -15,17 +15,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <map>
#include <list>
#include <string>
#include <vector>
#include <errno.h>
#include <regex>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <cstdint>
#include <stdint.h>
#include "bootctrl.h"
@ -107,7 +102,7 @@ int get_slot_info(struct slot_info *slots)
slots[active_slot].active = true;
for (size_t i = 0; i < 2; i++) {
for (int i = 0; i < 2; i++) {
rc = impl->isSlotMarkedSuccessful(i);
if (rc < 0)
return rc;
@ -130,7 +125,7 @@ void dump_info()
printf("Current slot: %s\n",
current_slot >= 0 ? impl->getSuffix(current_slot) : "N/A");
for (size_t i = 0; i < 2; i++) {
for (int i = 0; i < 2; i++) {
printf("SLOT %s:\n", impl->getSuffix(i));
printf("\tActive : %d\n", slots[i].active);
printf("\tSuccessful : %d\n", slots[i].successful);

@ -2,7 +2,7 @@
#define __UTILS_H__
// Enable debug logging
//#define DEBUG 1
// #define DEBUG 1
#ifdef DEBUG
#define LOGD(fmt, ...) printf(fmt, ##__VA_ARGS__)

Loading…
Cancel
Save