From 04f4ac81ea83a0e9674c3e943030af454419e7c4 Mon Sep 17 00:00:00 2001 From: Caleb Connolly Date: Fri, 23 Jun 2023 20:16:24 +0100 Subject: [PATCH] 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. --- .clang-format | 10 +- bootctrl_impl.cpp | 687 +++++++++++++++++++++------------------------- gpt-utils.cpp | 601 +++++++++++++++++++++------------------- gpt-utils.h | 7 +- meson.build | 8 +- qbootctl.cpp | 11 +- utils.h | 2 +- 7 files changed, 652 insertions(+), 674 deletions(-) diff --git a/.clang-format b/.clang-format index c9e15ea..82784d8 100644 --- a/.clang-format +++ b/.clang-format @@ -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 ... diff --git a/bootctrl_impl.cpp b/bootctrl_impl.cpp index 0f99038..0ff0af9 100644 --- a/bootctrl_impl.cpp +++ b/bootctrl_impl.cpp @@ -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 . + * along with this program. If not, see . */ -#include -#include -#include -#include +#include #include +#include +#include +#include +#include #include +#include #include #include -#include -#include -#include +#include #include -#include -#include -#include +#include +#include +#include -#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 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 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::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 > ptn_map; + map> ptn_map; vector 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 >::iterator map_iter; + map>::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]--> // [path_to_block_device_2]--> // ... @@ -638,19 +601,14 @@ int set_active_boot_slot(unsigned slot) // [/dev/block/sdb]---> 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, diff --git a/gpt-utils.cpp b/gpt-utils.cpp index 0af03cf..59ce60f 100644 --- a/gpt-utils.cpp +++ b/gpt-utils.cpp @@ -30,27 +30,28 @@ #define _LARGEFILE64_SOURCE /* enable lseek64() */ -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "assert.h" +#include #include +#include +#include +#include #include +#include +#include #include -#include #include -#include +#include +#include #include -#include +#include +#include +#include +#include #include -#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 &ptn_list, - map > &partition_map) +int gpt_utils_get_partition_map(vector &ptn_list, map> &partition_map) { char devpath[PATH_MAX] = { '\0' }; - map >::iterator it; + map>::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 &ptn_list, } else { vector str_vec; str_vec.push_back(ptn_list[i]); - partition_map.insert( - pair >(path, str_vec)); + partition_map.insert(pair>(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))) diff --git a/gpt-utils.h b/gpt-utils.h index 9e3b86f..a4eb9e4 100644 --- a/gpt-utils.h +++ b/gpt-utils.h @@ -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); diff --git a/meson.build b/meson.build index 3d3761d..afe7d3c 100644 --- a/meson.build +++ b/meson.build @@ -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', diff --git a/qbootctl.cpp b/qbootctl.cpp index 3559e29..a666b82 100644 --- a/qbootctl.cpp +++ b/qbootctl.cpp @@ -15,17 +15,12 @@ * along with this program. If not, see . */ -#include -#include -#include -#include #include -#include #include #include #include #include -#include +#include #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); diff --git a/utils.h b/utils.h index 9ac103f..3d7e920 100644 --- a/utils.h +++ b/utils.h @@ -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__)