diff --git a/bootctrl_impl.cpp b/bootctrl_impl.cpp index 59fcc7d..f13f296 100644 --- a/bootctrl_impl.cpp +++ b/bootctrl_impl.cpp @@ -68,26 +68,42 @@ 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) { - int fd; + file file; char pcmd[MAX_CMDLINE_SIZE]; char *val, *found, *ptr = buf; - fd = open("/proc/cmdline", O_RDONLY); - int rc = read(fd, pcmd, MAX_CMDLINE_SIZE); + file.open("/proc/cmdline"); + int rc = read(file.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++; @@ -103,28 +119,25 @@ error: static int get_partition_attribute(char *partname, enum part_attr_type part_attr) { - struct gpt_disk *disk = NULL; + struct gpt_disk disk; uint8_t *pentry = NULL; int retval = -1; uint8_t *attr = NULL; 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)) { + return retval; + + if (gpt_disk_get_disk_info(partname, &disk)) { fprintf(stderr, "%s: Failed to get disk info\n", __func__); - goto error; + return retval; } - 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__); - goto error; + return retval; } + attr = pentry + AB_FLAG_OFFSET; LOGD("get_partition_attribute() partname = %s, attr = 0x%x\n", partname, *attr); @@ -138,14 +151,8 @@ 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; } @@ -156,7 +163,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 = NULL; + struct gpt_disk disk; uint8_t *pentry = NULL; uint8_t *pentry_bak = NULL; int rc = -1; @@ -167,17 +174,20 @@ 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__); - 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]))) 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 @@ -197,26 +207,23 @@ 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); - 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); + 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; + return -1; } - 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); - goto error; + 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); @@ -241,42 +248,55 @@ static int update_slot_attribute(const char *slot, enum part_attr_type ab_attr) break; default: fprintf(stderr, "%s: Unrecognized attr\n", __func__); - goto error; + return -1; } - if (gpt_disk_update_crc(disk)) { + + if (gpt_disk_update_crc(&disk)) { fprintf(stderr, "%s: Failed to update crc for %s\n", __func__, partName); - goto error; + return -1; } - if (gpt_disk_commit(disk)) { + + 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; } + 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 = NULL; + dir dir_bootdev; unsigned slot_count = 0; - dir_bootdev = opendir(BOOTDEV_DIR); - if (!dir_bootdev) { + if (!dir_bootdev.open(BOOTDEV_DIR)) { fprintf(stderr, "%s: Failed to open bootdev dir (%s)\n", __func__, strerror(errno)); - goto error; + return 0; } - while ((de = readdir(dir_bootdev))) { + + while ((de = readdir(dir_bootdev.dir))) { if (de->d_name[0] == '.') continue; static_assert(AB_SLOT_A_SUFFIX[0] == '_', @@ -290,12 +310,8 @@ 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() @@ -308,12 +324,14 @@ static unsigned int get_current_slot() //Slot 0 is the only slot around. return 0; } + get_kernel_cmdline_arg(BOOT_SLOT_PROP, bootSlotProp, "_a"); if (!strncmp(bootSlotProp, "N/A\n", strlen("N/A"))) { fprintf(stderr, "%s: Unable to read boot slot property\n", __func__); - goto error; + return 0; } + //Iterate through a list of partitons named as boot+suffix //and see which one is currently active. for (i = 0; slot_suffix_arr[i] != NULL; i++) { @@ -323,7 +341,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. @@ -383,13 +401,12 @@ int mark_boot_successful(unsigned slot) if (update_slot_attribute(slot_suffix_arr[slot], ATTR_BOOT_SUCCESSFUL)) { - goto error; + fprintf(stderr, "SLOT %s: Failed to mark boot successful\n", + slot_suffix_arr[slot]); + return -1; } + 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) @@ -402,25 +419,17 @@ const char *get_suffix(unsigned slot) //Return a gpt disk structure representing the disk that holds //partition. -static struct gpt_disk *boot_ctl_get_disk_info(char *partition) +static bool boot_ctl_get_disk_info(char *partition, gpt_disk *disk) { - 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; - } + return false; + if (gpt_disk_get_disk_info(partition, disk)) { fprintf(stderr, "failed to get disk info for %s\n", partition); - goto error; + return false; } - return disk; -error: - if (disk) - gpt_disk_free(disk); - return NULL; + + return true; } //The argument here is a vector of partition names(including the slot suffix) @@ -429,7 +438,7 @@ static int boot_ctl_set_active_slot_for_partitions(vector part_list, unsigned slot) { char buf[PATH_MAX] = { 0 }; - struct gpt_disk *disk = NULL; + struct gpt_disk disk; char slotA[MAX_GPT_NAME_SIZE + 1] = { 0 }; char slotB[MAX_GPT_NAME_SIZE + 1] = { 0 }; char active_guid[TYPE_GUID_SIZE + 1] = { 0 }; @@ -455,8 +464,9 @@ 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()); - goto error; + 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, @@ -484,26 +494,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 (!disk) { - disk = boot_ctl_get_disk_info(slotA); - if (!disk) - goto error; - } + if (!boot_ctl_get_disk_info(slotA, &disk)) + return -1; + //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()); - goto error; + return -1; } + LOGD("\tAB attr (A): 0x%x (backup: 0x%x)\n", *(uint16_t *)(pentryA + AB_FLAG_OFFSET), *(uint16_t *)(pentryA_bak + AB_FLAG_OFFSET)); @@ -527,8 +537,9 @@ static int boot_ctl_set_active_slot_for_partitions(vector part_list, 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, @@ -554,28 +565,23 @@ 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__); - goto error; + return -1; } - 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__); - goto error; + return -1; } } + //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); + 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() @@ -607,13 +613,13 @@ int set_active_boot_slot(unsigned slot) if (boot_control_check_slot_sanity(slot)) { fprintf(stderr, "%s: Bad arguments\n", __func__); - goto error; + return -1; } ismmc = gpt_utils_is_partition_backed_by_emmc(PTN_XBL AB_SLOT_A_SUFFIX); if (!ismmc && ufs_bsg_dev_open() < 0) { - goto error; + return -1; } //The partition list just contains prefixes(without the _a/_b) of the @@ -629,6 +635,7 @@ int set_active_boot_slot(unsigned slot) cur_ptn.append(AB_SLOT_A_SUFFIX); ptn_vec.push_back(cur_ptn); } + //The partition map gives us info in the following format: // [path_to_block_device_1]--> // [path_to_block_device_2]--> @@ -638,8 +645,9 @@ 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; + return -1; } + for (map_iter = ptn_map.begin(); map_iter != ptn_map.end(); map_iter++) { if (map_iter->second.size() < 1) @@ -649,8 +657,7 @@ int set_active_boot_slot(unsigned slot) fprintf(stderr, "%s: Failed to set active slot for partitions \n", __func__); - ; - goto error; + return -1; } } @@ -669,19 +676,17 @@ int set_active_boot_slot(unsigned slot) } else { //Something has gone terribly terribly wrong fprintf(stderr, "%s: Unknown slot suffix!\n", __func__); - goto error; + return -1; } + if (rc) { fprintf(stderr, "%s: Failed to switch xbl boot partition\n", __func__); - goto error; + return -1; } return 0; - -error: - return -1; } int set_slot_as_unbootable(unsigned slot) @@ -706,15 +711,16 @@ int is_slot_marked_successful(unsigned slot) if (boot_control_check_slot_sanity(slot) != 0) { fprintf(stderr, "%s: Argument check failed\n", __func__); - goto error; + return -1; } + 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 8405f1e..f0ad56a 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__); - goto error; + return -1; } } 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__); - goto error; + return -1; } } else { fprintf(stderr, "%s: Invalid boot chain id\n", __func__); - goto error; + return -1; } + //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)); - goto error; + return -1; } + LOGD("%s: setting %s lun as boot lun\n", __func__, boot_dev); - if (set_boot_lun(boot_lun_id)) { - goto error; - } + if (set_boot_lun(boot_lun_id)) + return -1; + 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__); - goto error; + return 0; } + if (ioctl(fd, BLKSSZGET, &block_size) != 0) { fprintf(stderr, "%s: Failed to get GPT dev block size : %s\n", __func__, strerror(errno)); - goto error; + return 0; } + return block_size; -error: - return 0; } //Write the GPT header present in the passed in buffer back to the @@ -408,146 +408,150 @@ 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__); - goto error; + return -1; } + 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; + return -1; } + 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__); - goto error; + return -1; } + 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__); - goto error; + return -1; } + 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 uint8_t *gpt_get_header(const char *partname, enum gpt_instance instance) +static bool gpt_get_header(const char *partname, enum gpt_instance instance, + std::vector *hdr) { - uint8_t *hdr = NULL; char devpath[PATH_MAX] = { 0 }; off_t hdr_offset = 0; uint32_t block_size = 0; - int fd = -1; + file file; if (!partname) { fprintf(stderr, "%s: Invalid partition name\n", __func__); - goto error; + return false; } + 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; + return false; } - fd = open(devpath, O_RDWR); - if (fd < 0) { - fprintf(stderr, "%s: Failed to open %s : %s\n", __func__, + + if (file.open(devpath) < 0) { + fprintf(stderr, "%s: Failed to open %s: %s\n", __func__, devpath, strerror(errno)); - goto error; + return false; } - block_size = gpt_get_block_size(fd); + + block_size = gpt_get_block_size(file.fd); if (block_size == 0) { fprintf(stderr, "%s: Failed to get gpt block size for %s\n", __func__, partname); - goto error; + return false; } - hdr = (uint8_t *)calloc(block_size, 1); - if (!hdr) { - fprintf(stderr, - "%s: Failed to allocate memory for gpt header\n", - __func__); - } + hdr->resize(block_size); + std::fill(hdr->begin(), hdr->end(), 0); if (instance == PRIMARY_GPT) hdr_offset = block_size; - else { - hdr_offset = lseek64(fd, 0, SEEK_END) - block_size; - } + else + hdr_offset = lseek64(file.fd, 0, SEEK_END) - block_size; + if (hdr_offset < 0) { fprintf(stderr, "%s: Failed to get gpt header offset\n", __func__); - goto error; + return false; } - if (blk_rw(fd, 0, hdr_offset, hdr, block_size)) { + + if (blk_rw(file.fd, 0, hdr_offset, hdr->data(), block_size)) { fprintf(stderr, "%s: Failed to read GPT header from device\n", __func__); - goto error; - } - //DumpHex(hdr, block_size); - close(fd); - return hdr; -error: - if (fd >= 0) - close(fd); - if (hdr) - free(hdr); - return NULL; + return false; + } + + return true; } //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) +static bool gpt_get_pentry_arr(uint8_t *hdr, int fd, + std::vector *pentry_arr) { 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__); - goto error; + return false; } + block_size = gpt_get_block_size(fd); if (!block_size) { fprintf(stderr, "%s: Failed to get gpt block size for\n", __func__); - goto error; + return false; } + 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 = (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); + 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); if (rc) { fprintf(stderr, "%s: Failed to read partition entry array\n", __func__); - goto error; + return false; } - return pentry_arr; -error: - if (pentry_arr) - free(pentry_arr); - return NULL; + + return true; } static int gpt_set_pentry_arr(uint8_t *hdr, int fd, uint8_t *arr) @@ -559,14 +563,16 @@ 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__); - goto error; + return -1; } + block_size = gpt_get_block_size(fd); if (!block_size) { fprintf(stderr, "%s: Failed to get gpt block size for\n", __func__); - goto error; + return -1; } + 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); @@ -580,71 +586,40 @@ 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__); - goto error; + return -1; } - 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; + return 0; } //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) +int gpt_disk_get_disk_info(const char *dev, struct gpt_disk *disk) { - struct gpt_disk *disk = NULL; - int fd = -1; + file file; uint32_t gpt_header_size = 0; - if (!dsk || !dev) { + if (!disk || !dev) { fprintf(stderr, "%s: Invalid arguments\n", __func__); - goto error; + return -1; } - disk = dsk; - disk->hdr = gpt_get_header(dev, PRIMARY_GPT); - if (!disk->hdr) { + + gpt_get_header(dev, PRIMARY_GPT, &disk->hdr); + if (disk->hdr.empty()) { fprintf(stderr, "%s: Failed to get primary header\n", __func__); - goto error; + return -1; } - gpt_header_size = GET_4_BYTES(disk->hdr + HEADER_SIZE_OFFSET); + + gpt_header_size = GET_4_BYTES(disk->hdr.data() + 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, PRIMARY_GPT); - if (!disk->hdr_bak) { + 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()) { fprintf(stderr, "%s: Failed to get backup header\n", __func__); - goto error; + return -1; } - disk->hdr_bak_crc = crc32(0, disk->hdr_bak, gpt_header_size); + + disk->hdr_bak_crc = crc32(0, disk->hdr_bak.data(), gpt_header_size); //Descriptor for the block device. We will use this for further //modifications to the partition table @@ -652,42 +627,42 @@ int gpt_disk_get_disk_info(const char *dev, struct gpt_disk *dsk) sizeof(disk->devpath)) != 0) { fprintf(stderr, "%s: Failed to resolve path for %s\n", __func__, dev); - goto error; + return -1; } - fd = open(disk->devpath, O_RDWR); - if (fd < 0) { + + if (file.open(disk->devpath) < 0) { fprintf(stderr, "%s: Failed to open %s: %s\n", __func__, disk->devpath, strerror(errno)); - goto error; + return -1; } - disk->pentry_arr = gpt_get_pentry_arr(disk->hdr, fd); - if (!disk->pentry_arr) { + + gpt_get_pentry_arr(disk->hdr.data(), file.fd, &disk->pentry_arr); + if (disk->pentry_arr.empty()) { fprintf(stderr, "%s: Failed to obtain partition entry array\n", __func__); - goto error; + return -1; } - disk->pentry_arr_bak = gpt_get_pentry_arr(disk->hdr_bak, fd); - if (!disk->pentry_arr_bak) { + + gpt_get_pentry_arr(disk->hdr_bak.data(), file.fd, + &disk->pentry_arr_bak); + if (disk->pentry_arr_bak.empty()) { fprintf(stderr, "%s: Failed to obtain backup partition entry array\n", __func__); - goto error; + return -1; } - disk->pentry_size = GET_4_BYTES(disk->hdr + PENTRY_SIZE_OFFSET); + + disk->pentry_size = GET_4_BYTES(disk->hdr.data() + PENTRY_SIZE_OFFSET); disk->pentry_arr_size = - GET_4_BYTES(disk->hdr + PARTITION_COUNT_OFFSET) * + GET_4_BYTES(disk->hdr.data() + PARTITION_COUNT_OFFSET) * disk->pentry_size; - disk->pentry_arr_crc = GET_4_BYTES(disk->hdr + PARTITION_CRC_OFFSET); + disk->pentry_arr_crc = + GET_4_BYTES(disk->hdr.data() + 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); + GET_4_BYTES(disk->hdr_bak.data() + PARTITION_CRC_OFFSET); + disk->block_size = gpt_get_block_size(file.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 @@ -697,15 +672,14 @@ 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__); - goto error; + return NULL; } - ptn_arr = (instance == PRIMARY_GPT) ? disk->pentry_arr : - disk->pentry_arr_bak; + + ptn_arr = (instance == PRIMARY_GPT) ? disk->pentry_arr.data() : + disk->pentry_arr_bak.data(); 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 @@ -717,69 +691,68 @@ 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; + return -1; } + //Recalculate the CRC of the primary partiton array disk->pentry_arr_crc = - crc32(0, disk->pentry_arr, disk->pentry_arr_size); + crc32(0, disk->pentry_arr.data(), 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); + crc32(0, disk->pentry_arr_bak.data(), 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); + PUT_4_BYTES(disk->hdr.data() + 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, + PUT_4_BYTES(disk->hdr_bak.data() + 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); + gpt_header_size = GET_4_BYTES(disk->hdr.data() + HEADER_SIZE_OFFSET); //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); - 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); + 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); 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) { - int fd = -1; + file file; if (!disk || (disk->is_initialized != GPT_DISK_INIT_MAGIC)) { fprintf(stderr, "%s: Invalid args\n", __func__); - goto error; + return -1; } - fd = open(disk->devpath, O_RDWR); - if (fd < 0) { + + if (file.open(disk->devpath) < 0) { fprintf(stderr, "%s: Failed to open %s: %s\n", __func__, disk->devpath, strerror(errno)); - goto error; + return -1; } + LOGD("%s: Writing back primary GPT header\n", __func__); //Write the primary header - if (gpt_set_header(disk->hdr, fd, PRIMARY_GPT) != 0) { + if (gpt_set_header(disk->hdr.data(), file.fd, PRIMARY_GPT) != 0) { fprintf(stderr, "%s: Failed to update primary GPT header\n", __func__); - goto error; + return -1; } + LOGD("%s: Writing back primary partition array\n", __func__); //Write back the primary partition array - if (gpt_set_pentry_arr(disk->hdr, fd, disk->pentry_arr)) { + if (gpt_set_pentry_arr(disk->hdr.data(), file.fd, + disk->pentry_arr.data())) { fprintf(stderr, "%s: Failed to write primary GPT partition arr\n", __func__); - goto error; + return -1; } - 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 9e3b86f..775bcd8 100644 --- a/gpt-utils.h +++ b/gpt-utils.h @@ -96,36 +96,32 @@ enum boot_chain { NORMAL_BOOT = 0, BACKUP_BOOT }; struct gpt_disk { //GPT primary header - uint8_t *hdr; + std::vector hdr; //primary header crc - uint32_t hdr_crc; + uint32_t hdr_crc = 0; //GPT backup header - uint8_t *hdr_bak; + std::vector hdr_bak; //backup header crc - uint32_t hdr_bak_crc; + uint32_t hdr_bak_crc = 0; //Partition entries array - uint8_t *pentry_arr; + std::vector pentry_arr; //Partition entries array for backup table - uint8_t *pentry_arr_bak; + std::vector pentry_arr_bak; //Size of the pentry array - uint32_t pentry_arr_size; + uint32_t pentry_arr_size = 0; //Size of each element in the pentry array - uint32_t pentry_size; + uint32_t pentry_size = 0; //CRC of the partition entry array - uint32_t pentry_arr_crc; + uint32_t pentry_arr_crc = 0; //CRC of the backup partition entry array - uint32_t pentry_arr_bak_crc; + uint32_t pentry_arr_bak_crc = 0; //Path to block dev representing the disk - char devpath[PATH_MAX]; + char devpath[PATH_MAX] = { 0 }; //Block size of disk - uint32_t block_size; - uint32_t is_initialized; + uint32_t block_size = 0; + uint32_t is_initialized = 0; }; -//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 3559e29..c2095e1 100644 --- a/qbootctl.cpp +++ b/qbootctl.cpp @@ -41,17 +41,23 @@ 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)) { - goto fail; - } + if (!isslot(arg)) + unexpectedSlot(arg); + if (isslotnum(arg)) { slot = (int)strtol(arg, &end, 10); if (end == arg) - goto fail; + unexpectedSlot(arg); } else { switch (arg[0]) { case 'a': @@ -63,17 +69,11 @@ unsigned parseSlot(const char* arg) slot = 1; break; default: - goto fail; + unexpectedSlot(arg); } } 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 8b66342..b7dfb2d 100644 --- a/ufs-bsg.cpp +++ b/ufs-bsg.cpp @@ -48,34 +48,43 @@ /* UFS BSG device node */ static char ufs_bsg_dev[FNAME_SZ] = "/dev/bsg/ufs-bsg0"; -static int fd_ufs_bsg = 0; +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; int ufs_bsg_dev_open() { - if (fd_ufs_bsg) + if (fd_ufs_bsg.fd) return 0; - fd_ufs_bsg = open(ufs_bsg_dev, O_RDWR); - if (fd_ufs_bsg < 0) { + fd_ufs_bsg.fd = open(ufs_bsg_dev, O_RDWR); + if (fd_ufs_bsg.fd < 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 = 0; + fd_ufs_bsg.fd = 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) @@ -171,18 +180,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, 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.fd, 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; } -out: - ufs_bsg_dev_close(); + + fd_ufs_bsg.close(); return ret; }