diff --git a/bootctrl_impl.cpp b/bootctrl_impl.cpp index d375631..0f99038 100644 --- a/bootctrl_impl.cpp +++ b/bootctrl_impl.cpp @@ -68,42 +68,26 @@ enum part_attr_type { ATTR_BOOTABLE, }; -struct file { - int fd = -1; - - ~file() - { - if (fd > -1) - close(fd); - } - - int open(const char *path) - { - fd = ::open(path, O_RDONLY); - return fd; - } -}; - void get_kernel_cmdline_arg(const char *arg, char *buf, const char *def) { - file file; + int fd; char pcmd[MAX_CMDLINE_SIZE]; char *val, *found, *ptr = buf; - file.open("/proc/cmdline"); - int rc = read(file.fd, pcmd, MAX_CMDLINE_SIZE); + 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)); goto error; } - + close(fd); found = strstr(pcmd, arg); if (!found || !(val = strstr(found, "="))) { fprintf(stderr, "Couldn't find cmdline arg: '%s'\n", arg); goto error; } - ++val; + val++; // no this doesn't handle quotes lol while (*val != ' ') { *ptr++ = *val++; @@ -119,25 +103,28 @@ error: static int get_partition_attribute(char *partname, enum part_attr_type part_attr) { - struct gpt_disk disk; + struct gpt_disk *disk = NULL; uint8_t *pentry = NULL; int retval = -1; uint8_t *attr = NULL; if (!partname) - return retval; - - if (gpt_disk_get_disk_info(partname, &disk)) { + 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__); - return retval; + goto error; } + pentry = gpt_disk_get_pentry(disk, partname, PRIMARY_GPT); - pentry = gpt_disk_get_pentry(&disk, partname, PRIMARY_GPT); if (!pentry) { fprintf(stderr, "%s: pentry does not exist in disk struct\n", __func__); - return retval; + goto error; } - attr = pentry + AB_FLAG_OFFSET; LOGD("get_partition_attribute() partname = %s, attr = 0x%x\n", partname, *attr); @@ -151,8 +138,14 @@ static int get_partition_attribute(char *partname, } else if (part_attr == ATTR_UNBOOTABLE) { retval = !!(*attr & AB_PARTITION_ATTR_UNBOOTABLE); LOGD("AB_PARTITION_ATTR_UNBOOTABLE, retval = %d\n", retval); + } else { + retval = -1; } - + gpt_disk_free(disk); + return retval; +error: + if (disk) + gpt_disk_free(disk); return retval; } @@ -163,7 +156,7 @@ static int update_slot_attribute(const char *slot, enum part_attr_type ab_attr) unsigned int i = 0; char buf[PATH_MAX]; struct stat st; - struct gpt_disk disk; + struct gpt_disk *disk = NULL; uint8_t *pentry = NULL; uint8_t *pentry_bak = NULL; int rc = -1; @@ -174,20 +167,17 @@ static int update_slot_attribute(const char *slot, enum part_attr_type ab_attr) int slot_name_valid = 0; if (!slot) { fprintf(stderr, "%s: Invalid argument\n", __func__); - return -1; + goto error; } - for (i = 0; slot_suffix_arr[i] != NULL; 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__); - return -1; + goto error; } - for (i = 0; i < ARRAY_SIZE(ptn_list); i++) { memset(buf, '\0', sizeof(buf)); //Check if A/B versions of this ptn exist @@ -207,23 +197,26 @@ static int update_slot_attribute(const char *slot, enum part_attr_type ab_attr) memset(partName, '\0', sizeof(partName)); snprintf(partName, sizeof(partName) - 1, "%s%s", ptn_list[i], slot); - rc = gpt_disk_get_disk_info(partName, &disk); + disk = gpt_disk_alloc(); + if (!disk) { + fprintf(stderr, "%s: Failed to alloc disk struct\n", + __func__); + goto error; + } + rc = gpt_disk_get_disk_info(partName, disk); if (rc != 0) { fprintf(stderr, "%s: Failed to get disk info for %s\n", __func__, partName); - return -1; + goto error; } - - pentry = gpt_disk_get_pentry(&disk, partName, PRIMARY_GPT); - pentry_bak = - gpt_disk_get_pentry(&disk, partName, SECONDARY_GPT); + 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); - return -1; + goto error; } - 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); @@ -248,55 +241,42 @@ static int update_slot_attribute(const char *slot, enum part_attr_type ab_attr) break; default: fprintf(stderr, "%s: Unrecognized attr\n", __func__); - return -1; + goto error; } - - if (gpt_disk_update_crc(&disk)) { + if (gpt_disk_update_crc(disk)) { fprintf(stderr, "%s: Failed to update crc for %s\n", __func__, partName); - return -1; + goto error; } - - if (gpt_disk_commit(&disk)) { + if (gpt_disk_commit(disk)) { fprintf(stderr, "%s: Failed to write back entry for %s\n", __func__, partName); - return -1; + goto error; } + gpt_disk_free(disk); + disk = NULL; } - return 0; +error: + if (disk) + gpt_disk_free(disk); + return -1; } -struct dir { - DIR *dir = NULL; - - ~dir() - { - if (dir) - closedir(dir); - } - - DIR *open(const char *name) - { - dir = opendir(name); - return dir; - } -}; - unsigned get_number_slots() { struct dirent *de = NULL; - dir dir_bootdev; + DIR *dir_bootdev = NULL; unsigned slot_count = 0; - if (!dir_bootdev.open(BOOTDEV_DIR)) { + dir_bootdev = opendir(BOOTDEV_DIR); + if (!dir_bootdev) { fprintf(stderr, "%s: Failed to open bootdev dir (%s)\n", __func__, strerror(errno)); - return 0; + goto error; } - - while ((de = readdir(dir_bootdev.dir))) { + while ((de = readdir(dir_bootdev))) { if (de->d_name[0] == '.') continue; static_assert(AB_SLOT_A_SUFFIX[0] == '_', @@ -310,8 +290,12 @@ unsigned get_number_slots() slot_count++; } } - + closedir(dir_bootdev); return slot_count; +error: + if (dir_bootdev) + closedir(dir_bootdev); + return 0; } static unsigned int get_current_slot() @@ -324,14 +308,12 @@ static unsigned int get_current_slot() //Slot 0 is the only slot around. return 0; } - get_kernel_cmdline_arg(BOOT_SLOT_PROP, bootSlotProp, "_a"); if (!strncmp(bootSlotProp, "N/A\n", strlen("N/A"))) { fprintf(stderr, "%s: Unable to read boot slot property\n", __func__); - return 0; + 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++) { @@ -341,7 +323,7 @@ static unsigned int get_current_slot() 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. @@ -401,12 +383,13 @@ int mark_boot_successful(unsigned slot) if (update_slot_attribute(slot_suffix_arr[slot], ATTR_BOOT_SUCCESSFUL)) { - fprintf(stderr, "SLOT %s: Failed to mark boot successful\n", - slot_suffix_arr[slot]); - return -1; + goto error; } - return 0; +error: + fprintf(stderr, "SLOT %s: Failed to mark boot successful\n", + slot_suffix_arr[slot]); + return -1; } const char *get_suffix(unsigned slot) @@ -419,17 +402,25 @@ const char *get_suffix(unsigned slot) //Return a gpt disk structure representing the disk that holds //partition. -static bool boot_ctl_get_disk_info(char *partition, gpt_disk *disk) +static struct gpt_disk *boot_ctl_get_disk_info(char *partition) { + struct gpt_disk *disk = NULL; if (!partition) - return false; - + 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); - return false; + goto error; } - - return true; + return disk; +error: + if (disk) + gpt_disk_free(disk); + return NULL; } //The argument here is a vector of partition names(including the slot suffix) @@ -438,7 +429,7 @@ static int boot_ctl_set_active_slot_for_partitions(vector part_list, unsigned slot) { char buf[PATH_MAX] = { 0 }; - struct gpt_disk disk; + 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 }; @@ -464,9 +455,8 @@ static int boot_ctl_set_active_slot_for_partitions(vector part_list, if (prefix.size() < (strlen(AB_SLOT_A_SUFFIX) + 1)) { fprintf(stderr, "Invalid partition name: %s\n", prefix.c_str()); - return -1; + goto error; } - 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, @@ -494,26 +484,26 @@ static int boot_ctl_set_active_slot_for_partitions(vector part_list, 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 (!boot_ctl_get_disk_info(slotA, &disk)) - return -1; - + if (!disk) { + disk = boot_ctl_get_disk_info(slotA); + if (!disk) + goto error; + } //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); + 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()); - return -1; + goto error; } - LOGD("\tAB attr (A): 0x%x (backup: 0x%x)\n", *(uint16_t *)(pentryA + AB_FLAG_OFFSET), *(uint16_t *)(pentryA_bak + AB_FLAG_OFFSET)); @@ -537,9 +527,8 @@ static int boot_ctl_set_active_slot_for_partitions(vector part_list, TYPE_GUID_SIZE); } else { fprintf(stderr, "Both A & B are inactive..Aborting"); - return -1; + goto error; } - // printf("\tActive GUID: %s\n", active_guid); // printf("\tInactive GUID: %s\n", active_guid); if (!strncmp(slot_suffix_arr[slot], AB_SLOT_A_SUFFIX, @@ -565,23 +554,28 @@ static int boot_ctl_set_active_slot_for_partitions(vector part_list, } else { //Something has gone terribly terribly wrong fprintf(stderr, "%s: Unknown slot suffix!\n", __func__); - return -1; + goto error; } - - if (gpt_disk_update_crc(&disk) != 0) { + if (gpt_disk_update_crc(disk) != 0) { fprintf(stderr, "%s: Failed to update gpt_disk crc\n", __func__); - return -1; + goto error; } } - //write updated content to disk - if (gpt_disk_commit(&disk)) { - fprintf(stderr, "Failed to commit disk entry"); - return -1; + if (disk) { + if (gpt_disk_commit(disk)) { + fprintf(stderr, "Failed to commit disk entry"); + goto error; + } + gpt_disk_free(disk); } - return 0; + +error: + if (disk) + gpt_disk_free(disk); + return -1; } unsigned get_active_boot_slot() @@ -613,13 +607,13 @@ int set_active_boot_slot(unsigned slot) if (boot_control_check_slot_sanity(slot)) { fprintf(stderr, "%s: Bad arguments\n", __func__); - return -1; + goto error; } ismmc = gpt_utils_is_partition_backed_by_emmc(PTN_XBL AB_SLOT_A_SUFFIX); if (!ismmc && ufs_bsg_dev_open() < 0) { - return -1; + goto error; } //The partition list just contains prefixes(without the _a/_b) of the @@ -635,7 +629,6 @@ int set_active_boot_slot(unsigned slot) cur_ptn.append(AB_SLOT_A_SUFFIX); ptn_vec.push_back(cur_ptn); } - //The partition map gives us info in the following format: // [path_to_block_device_1]--> // [path_to_block_device_2]--> @@ -645,9 +638,8 @@ 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__); - return -1; + goto error; } - for (map_iter = ptn_map.begin(); map_iter != ptn_map.end(); map_iter++) { if (map_iter->second.size() < 1) @@ -657,7 +649,8 @@ int set_active_boot_slot(unsigned slot) fprintf(stderr, "%s: Failed to set active slot for partitions \n", __func__); - return -1; + ; + goto error; } } @@ -676,17 +669,19 @@ int set_active_boot_slot(unsigned slot) } else { //Something has gone terribly terribly wrong fprintf(stderr, "%s: Unknown slot suffix!\n", __func__); - return -1; + goto error; } - if (rc) { fprintf(stderr, "%s: Failed to switch xbl boot partition\n", __func__); - return -1; + goto error; } return 0; + +error: + return -1; } int set_slot_as_unbootable(unsigned slot) @@ -711,16 +706,15 @@ int is_slot_marked_successful(unsigned slot) if (boot_control_check_slot_sanity(slot) != 0) { fprintf(stderr, "%s: Argument check failed\n", __func__); - return -1; + 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; } diff --git a/gpt-utils.cpp b/gpt-utils.cpp index f0ad56a..8405f1e 100644 --- a/gpt-utils.cpp +++ b/gpt-utils.cpp @@ -272,7 +272,7 @@ int gpt_utils_set_xbl_boot_partition(enum boot_chain chain) else { fprintf(stderr, "%s: Failed to locate secondary xbl\n", __func__); - return -1; + goto error; } } else if (chain == NORMAL_BOOT) { boot_lun_id = BOOT_LUN_A_ID; @@ -283,28 +283,28 @@ int gpt_utils_set_xbl_boot_partition(enum boot_chain chain) else { fprintf(stderr, "%s: Failed to locate primary xbl\n", __func__); - return -1; + goto error; } } else { fprintf(stderr, "%s: Invalid boot chain id\n", __func__); - return -1; + 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. 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)); - return -1; + goto error; } - LOGD("%s: setting %s lun as boot lun\n", __func__, boot_dev); - if (set_boot_lun(boot_lun_id)) - return -1; - + if (set_boot_lun(boot_lun_id)) { + goto error; + } return 0; +error: + return -1; } //Given a parttion name(eg: rpm) get the path to the block device that @@ -387,16 +387,16 @@ static uint32_t gpt_get_block_size(int fd) uint32_t block_size = 0; if (fd < 0) { fprintf(stderr, "%s: invalid descriptor\n", __func__); - return 0; + goto error; } - if (ioctl(fd, BLKSSZGET, &block_size) != 0) { fprintf(stderr, "%s: Failed to get GPT dev block size : %s\n", __func__, strerror(errno)); - return 0; + goto error; } - return block_size; +error: + return 0; } //Write the GPT header present in the passed in buffer back to the @@ -408,150 +408,146 @@ static int gpt_set_header(uint8_t *gpt_header, int fd, off_t gpt_header_offset = 0; if (!gpt_header || fd < 0) { fprintf(stderr, "%s: Invalid arguments\n", __func__); - return -1; + 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__); - return -1; + 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__); - return -1; + goto error; } - 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__); - return -1; + goto error; } - return 0; +error: + return -1; } -struct file { - int fd = -1; - - ~file() - { - if (fd > -1) { - fsync(fd); - close(fd); - } - } - - int open(const char *path) - { - fd = ::open(path, O_RDWR); - return fd; - } -}; - //Read out the GPT header for the disk that contains the partition partname -static bool gpt_get_header(const char *partname, enum gpt_instance instance, - std::vector *hdr) +static uint8_t *gpt_get_header(const char *partname, enum gpt_instance instance) { + uint8_t *hdr = NULL; char devpath[PATH_MAX] = { 0 }; off_t hdr_offset = 0; uint32_t block_size = 0; - file file; + int fd = -1; if (!partname) { fprintf(stderr, "%s: Invalid partition name\n", __func__); - return false; + 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); - return false; + goto error; } - - if (file.open(devpath) < 0) { - fprintf(stderr, "%s: Failed to open %s: %s\n", __func__, + fd = open(devpath, O_RDWR); + if (fd < 0) { + fprintf(stderr, "%s: Failed to open %s : %s\n", __func__, devpath, strerror(errno)); - return false; + goto error; } - - block_size = gpt_get_block_size(file.fd); + 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); - return false; + goto error; } - hdr->resize(block_size); - std::fill(hdr->begin(), hdr->end(), 0); + 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(file.fd, 0, SEEK_END) - 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__); - return false; + goto error; } - - if (blk_rw(file.fd, 0, hdr_offset, hdr->data(), block_size)) { + if (blk_rw(fd, 0, hdr_offset, hdr, block_size)) { fprintf(stderr, "%s: Failed to read GPT header from device\n", __func__); - return false; - } - - return true; + goto error; + } + //DumpHex(hdr, block_size); + close(fd); + return hdr; +error: + if (fd >= 0) + close(fd); + if (hdr) + free(hdr); + return NULL; } //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 bool gpt_get_pentry_arr(uint8_t *hdr, int fd, - std::vector *pentry_arr) +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; int rc = 0; + if (!hdr) { + fprintf(stderr, "%s: Invalid header\n", __func__); + goto error; + } if (fd < 0) { fprintf(stderr, "%s: Invalid fd\n", __func__); - return false; + goto error; } - block_size = gpt_get_block_size(fd); if (!block_size) { fprintf(stderr, "%s: Failed to get gpt block size for\n", __func__); - return false; + 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; - pentry_arr->resize(pentries_arr_size); - std::fill(pentry_arr->begin(), pentry_arr->end(), 0); - rc = blk_rw(fd, 0, pentries_start, pentry_arr->data(), - pentries_arr_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__); + 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__); - return false; + goto error; } - - return true; + return pentry_arr; +error: + if (pentry_arr) + free(pentry_arr); + return NULL; } static int gpt_set_pentry_arr(uint8_t *hdr, int fd, uint8_t *arr) @@ -563,16 +559,14 @@ static int gpt_set_pentry_arr(uint8_t *hdr, int fd, uint8_t *arr) int rc = 0; if (!hdr || fd < 0 || !arr) { fprintf(stderr, "%s: Invalid argument\n", __func__); - return -1; + goto error; } - block_size = gpt_get_block_size(fd); if (!block_size) { fprintf(stderr, "%s: Failed to get gpt block size for\n", __func__); - return -1; + 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); @@ -586,40 +580,71 @@ static int gpt_set_pentry_arr(uint8_t *hdr, int fd, uint8_t *arr) if (rc) { fprintf(stderr, "%s: Failed to read partition entry array\n", __func__); - return -1; + goto error; } - return 0; +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 +void gpt_disk_free(struct gpt_disk *disk) +{ + if (!disk) + return; + if (disk->hdr) + free(disk->hdr); + if (disk->hdr_bak) + free(disk->hdr_bak); + if (disk->pentry_arr) + free(disk->pentry_arr); + if (disk->pentry_arr_bak) + free(disk->pentry_arr_bak); + free(disk); + 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 *disk) +int gpt_disk_get_disk_info(const char *dev, struct gpt_disk *dsk) { - file file; + struct gpt_disk *disk = NULL; + int fd = -1; uint32_t gpt_header_size = 0; - if (!disk || !dev) { + if (!dsk || !dev) { fprintf(stderr, "%s: Invalid arguments\n", __func__); - return -1; + goto error; } - - gpt_get_header(dev, PRIMARY_GPT, &disk->hdr); - if (disk->hdr.empty()) { + disk = dsk; + disk->hdr = gpt_get_header(dev, PRIMARY_GPT); + if (!disk->hdr) { fprintf(stderr, "%s: Failed to get primary header\n", __func__); - return -1; + goto error; } - - gpt_header_size = GET_4_BYTES(disk->hdr.data() + HEADER_SIZE_OFFSET); + gpt_header_size = GET_4_BYTES(disk->hdr + HEADER_SIZE_OFFSET); // FIXME: pointer offsets crc bleh - disk->hdr_crc = crc32(0, disk->hdr.data(), gpt_header_size); - gpt_get_header(dev, PRIMARY_GPT, &disk->hdr_bak); - if (disk->hdr_bak.empty()) { + disk->hdr_crc = crc32(0, disk->hdr, gpt_header_size); + disk->hdr_bak = gpt_get_header(dev, PRIMARY_GPT); + if (!disk->hdr_bak) { fprintf(stderr, "%s: Failed to get backup header\n", __func__); - return -1; + goto error; } - - disk->hdr_bak_crc = crc32(0, disk->hdr_bak.data(), gpt_header_size); + 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 @@ -627,42 +652,42 @@ int gpt_disk_get_disk_info(const char *dev, struct gpt_disk *disk) sizeof(disk->devpath)) != 0) { fprintf(stderr, "%s: Failed to resolve path for %s\n", __func__, dev); - return -1; + goto error; } - - if (file.open(disk->devpath) < 0) { + fd = open(disk->devpath, O_RDWR); + if (fd < 0) { fprintf(stderr, "%s: Failed to open %s: %s\n", __func__, disk->devpath, strerror(errno)); - return -1; + goto error; } - - gpt_get_pentry_arr(disk->hdr.data(), file.fd, &disk->pentry_arr); - if (disk->pentry_arr.empty()) { + 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__); - return -1; + goto error; } - - gpt_get_pentry_arr(disk->hdr_bak.data(), file.fd, - &disk->pentry_arr_bak); - if (disk->pentry_arr_bak.empty()) { + 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__); - return -1; + goto error; } - - disk->pentry_size = GET_4_BYTES(disk->hdr.data() + PENTRY_SIZE_OFFSET); + disk->pentry_size = GET_4_BYTES(disk->hdr + PENTRY_SIZE_OFFSET); disk->pentry_arr_size = - GET_4_BYTES(disk->hdr.data() + PARTITION_COUNT_OFFSET) * + GET_4_BYTES(disk->hdr + PARTITION_COUNT_OFFSET) * disk->pentry_size; - disk->pentry_arr_crc = - GET_4_BYTES(disk->hdr.data() + PARTITION_CRC_OFFSET); + disk->pentry_arr_crc = GET_4_BYTES(disk->hdr + PARTITION_CRC_OFFSET); disk->pentry_arr_bak_crc = - GET_4_BYTES(disk->hdr_bak.data() + PARTITION_CRC_OFFSET); - disk->block_size = gpt_get_block_size(file.fd); + 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; return 0; +error: + if (fd >= 0) + close(fd); + return -1; } //Get pointer to partition entry from a allocated gpt_disk structure @@ -672,14 +697,15 @@ uint8_t *gpt_disk_get_pentry(struct gpt_disk *disk, const char *partname, uint8_t *ptn_arr = NULL; if (!disk || !partname || disk->is_initialized != GPT_DISK_INIT_MAGIC) { fprintf(stderr, "%s: Invalid argument\n", __func__); - return NULL; + goto error; } - - ptn_arr = (instance == PRIMARY_GPT) ? disk->pentry_arr.data() : - disk->pentry_arr_bak.data(); + 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 @@ -691,68 +717,69 @@ 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__); - return -1; + goto error; } - //Recalculate the CRC of the primary partiton array disk->pentry_arr_crc = - crc32(0, disk->pentry_arr.data(), disk->pentry_arr_size); + 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.data(), disk->pentry_arr_size); + 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.data() + PARTITION_CRC_OFFSET, - disk->pentry_arr_crc); + 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.data() + PARTITION_CRC_OFFSET, + 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.data() + HEADER_SIZE_OFFSET); + gpt_header_size = GET_4_BYTES(disk->hdr + HEADER_SIZE_OFFSET); //Header CRC is calculated with its own CRC field set to 0 - PUT_4_BYTES(disk->hdr.data() + HEADER_CRC_OFFSET, 0); - PUT_4_BYTES(disk->hdr_bak.data() + HEADER_CRC_OFFSET, 0); - disk->hdr_crc = crc32(0, disk->hdr.data(), gpt_header_size); - disk->hdr_bak_crc = crc32(0, disk->hdr_bak.data(), gpt_header_size); - PUT_4_BYTES(disk->hdr.data() + HEADER_CRC_OFFSET, disk->hdr_crc); - PUT_4_BYTES(disk->hdr_bak.data() + HEADER_CRC_OFFSET, - disk->hdr_bak_crc); + 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); + disk->hdr_bak_crc = crc32(0, disk->hdr_bak, gpt_header_size); + 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 int gpt_disk_commit(struct gpt_disk *disk) { - file file; + int fd = -1; if (!disk || (disk->is_initialized != GPT_DISK_INIT_MAGIC)) { fprintf(stderr, "%s: Invalid args\n", __func__); - return -1; + goto error; } - - if (file.open(disk->devpath) < 0) { + fd = open(disk->devpath, O_RDWR); + if (fd < 0) { fprintf(stderr, "%s: Failed to open %s: %s\n", __func__, disk->devpath, strerror(errno)); - return -1; + goto error; } - LOGD("%s: Writing back primary GPT header\n", __func__); //Write the primary header - if (gpt_set_header(disk->hdr.data(), file.fd, PRIMARY_GPT) != 0) { + if (gpt_set_header(disk->hdr, fd, PRIMARY_GPT) != 0) { fprintf(stderr, "%s: Failed to update primary GPT header\n", __func__); - return -1; + goto error; } - LOGD("%s: Writing back primary partition array\n", __func__); //Write back the primary partition array - if (gpt_set_pentry_arr(disk->hdr.data(), file.fd, - disk->pentry_arr.data())) { + if (gpt_set_pentry_arr(disk->hdr, fd, disk->pentry_arr)) { fprintf(stderr, "%s: Failed to write primary GPT partition arr\n", __func__); - return -1; + goto error; } - + fsync(fd); + close(fd); return 0; +error: + if (fd >= 0) + close(fd); + return -1; } //Determine whether to handle the given partition as eMMC or UFS, using the diff --git a/gpt-utils.h b/gpt-utils.h index 775bcd8..9e3b86f 100644 --- a/gpt-utils.h +++ b/gpt-utils.h @@ -96,32 +96,36 @@ enum boot_chain { NORMAL_BOOT = 0, BACKUP_BOOT }; struct gpt_disk { //GPT primary header - std::vector hdr; + uint8_t *hdr; //primary header crc - uint32_t hdr_crc = 0; + uint32_t hdr_crc; //GPT backup header - std::vector hdr_bak; + uint8_t *hdr_bak; //backup header crc - uint32_t hdr_bak_crc = 0; + uint32_t hdr_bak_crc; //Partition entries array - std::vector pentry_arr; + uint8_t *pentry_arr; //Partition entries array for backup table - std::vector pentry_arr_bak; + uint8_t *pentry_arr_bak; //Size of the pentry array - uint32_t pentry_arr_size = 0; + uint32_t pentry_arr_size; //Size of each element in the pentry array - uint32_t pentry_size = 0; + uint32_t pentry_size; //CRC of the partition entry array - uint32_t pentry_arr_crc = 0; + uint32_t pentry_arr_crc; //CRC of the backup partition entry array - uint32_t pentry_arr_bak_crc = 0; + uint32_t pentry_arr_bak_crc; //Path to block dev representing the disk - char devpath[PATH_MAX] = { 0 }; + char devpath[PATH_MAX]; //Block size of disk - uint32_t block_size = 0; - uint32_t is_initialized = 0; + uint32_t block_size; + uint32_t is_initialized; }; +//GPT disk methods +struct gpt_disk *gpt_disk_alloc(); +//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); diff --git a/qbootctl.cpp b/qbootctl.cpp index c2095e1..3559e29 100644 --- a/qbootctl.cpp +++ b/qbootctl.cpp @@ -41,23 +41,17 @@ bool isslotnum(const char* str) return strspn(str, "01") == strlen(str); } -static void unexpectedSlot(const char *arg) -{ - fprintf(stderr, "Expected slot not '%s'\n", arg); - exit(1); -} - unsigned parseSlot(const char* arg) { char *end; int slot; - if (!isslot(arg)) - unexpectedSlot(arg); - + if (!isslot(arg)) { + goto fail; + } if (isslotnum(arg)) { slot = (int)strtol(arg, &end, 10); if (end == arg) - unexpectedSlot(arg); + goto fail; } else { switch (arg[0]) { case 'a': @@ -69,11 +63,17 @@ unsigned parseSlot(const char* arg) slot = 1; break; default: - unexpectedSlot(arg); + goto fail; } } return (unsigned)slot; + +fail: + fprintf(stderr, + "Expected slot not '%s'\n", + arg); + exit(1); } int usage() diff --git a/ufs-bsg.cpp b/ufs-bsg.cpp index b7dfb2d..8b66342 100644 --- a/ufs-bsg.cpp +++ b/ufs-bsg.cpp @@ -48,43 +48,34 @@ /* UFS BSG device node */ static char ufs_bsg_dev[FNAME_SZ] = "/dev/bsg/ufs-bsg0"; -struct fd_ufs_bsg { - int fd = 0; - - ~fd_ufs_bsg() - { - close(); - } - - void close() - { - if (fd > 0) { - ::close(fd); - fd = 0; - } - } -}; - -static fd_ufs_bsg fd_ufs_bsg; +static int fd_ufs_bsg = 0; int ufs_bsg_dev_open() { - if (fd_ufs_bsg.fd) + if (fd_ufs_bsg) return 0; - fd_ufs_bsg.fd = open(ufs_bsg_dev, O_RDWR); - if (fd_ufs_bsg.fd < 0) { + fd_ufs_bsg = open(ufs_bsg_dev, O_RDWR); + if (fd_ufs_bsg < 0) { fprintf(stderr, "Unable to open '%s': %s\n", ufs_bsg_dev, strerror(errno)); fprintf(stderr, "Is CONFIG_SCSI_UFS_BSG is enabled in your kernel?\n"); - fd_ufs_bsg.fd = 0; + fd_ufs_bsg = 0; return -1; } return 0; } +void ufs_bsg_dev_close() +{ + if (fd_ufs_bsg) { + close(fd_ufs_bsg); + fd_ufs_bsg = 0; + } +} + static int ufs_bsg_ioctl(int fd, struct ufs_bsg_request *req, struct ufs_bsg_reply *rsp, __u8 *buf, __u32 buf_len, enum bsg_ioctl_dir dir) @@ -180,18 +171,18 @@ int32_t set_boot_lun(__u8 lun_id) ret = ufs_bsg_dev_open(); if (ret) return ret; - LOGD("Opened ufs bsg dev: %s\n", ufs_bsg_dev); - ret = ufs_query_attr(fd_ufs_bsg.fd, boot_lun_id, - QUERY_REQ_FUNC_STD_WRITE, QUERY_REQ_OP_WRITE_ATTR, - QUERY_ATTR_IDN_BOOT_LU_EN, 0, 0); + ret = ufs_query_attr(fd_ufs_bsg, boot_lun_id, QUERY_REQ_FUNC_STD_WRITE, + QUERY_REQ_OP_WRITE_ATTR, QUERY_ATTR_IDN_BOOT_LU_EN, + 0, 0); if (ret) { fprintf(stderr, "Error requesting ufs attr idn %d via query ioctl (return value: %d, error no: %d)", QUERY_ATTR_IDN_BOOT_LU_EN, ret, errno); + goto out; } - - fd_ufs_bsg.close(); +out: + ufs_bsg_dev_close(); return ret; }