diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk index 8ed5cc9d6..5e6c6f94f 100644 --- a/fs_mgr/Android.mk +++ b/fs_mgr/Android.mk @@ -4,7 +4,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= fs_mgr.c fs_mgr_verity.c fs_mgr_fstab.c -LOCAL_SRC_FILES += fs_mgr_format.c +LOCAL_SRC_FILES += fs_mgr_format.c fs_mgr_slotselect.c LOCAL_C_INCLUDES := $(LOCAL_PATH)/include \ system/vold \ @@ -13,7 +13,8 @@ LOCAL_C_INCLUDES := $(LOCAL_PATH)/include \ LOCAL_MODULE:= libfs_mgr LOCAL_STATIC_LIBRARIES := liblogwrap libmincrypt libext4_utils_static libsquashfs_utils -LOCAL_C_INCLUDES += system/extras/ext4_utils system/extras/squashfs_utils +LOCAL_C_INCLUDES += system/extras/ext4_utils system/extras/squashfs_utils \ + bootable/recovery LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_CFLAGS := -Werror diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c index a44d03458..4a92d2188 100644 --- a/fs_mgr/fs_mgr_fstab.c +++ b/fs_mgr/fs_mgr_fstab.c @@ -22,8 +22,6 @@ #include #include -#include - #include "fs_mgr_priv.h" struct fs_mgr_flag_values { @@ -332,25 +330,12 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path) fstab->recs[cnt].partnum = flag_vals.partnum; fstab->recs[cnt].swap_prio = flag_vals.swap_prio; fstab->recs[cnt].zram_size = flag_vals.zram_size; - - /* If an A/B partition, modify block device to be the real block device */ - if (fstab->recs[cnt].fs_mgr_flags & MF_SLOTSELECT) { - char propbuf[PROPERTY_VALUE_MAX]; - char *tmp; - - /* use the kernel parameter if set */ - property_get("ro.boot.slot_suffix", propbuf, ""); - - if (asprintf(&tmp, "%s%s", fstab->recs[cnt].blk_device, propbuf) > 0) { - free(fstab->recs[cnt].blk_device); - fstab->recs[cnt].blk_device = tmp; - } else { - ERROR("Error updating block device name\n"); - goto err; - } - } cnt++; } + /* If an A/B partition, modify block device to be the real block device */ + if (fs_mgr_update_for_slotselect(fstab) != 0) { + ERROR("Error updating for slotselect\n"); + } fclose(fstab_file); free(line); return fstab; diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h index a87092efc..367ab6e28 100644 --- a/fs_mgr/fs_mgr_priv.h +++ b/fs_mgr/fs_mgr_priv.h @@ -84,5 +84,6 @@ #define DM_BUF_SIZE 4096 int fs_mgr_set_blk_ro(const char *blockdev); +int fs_mgr_update_for_slotselect(struct fstab *fstab); #endif /* __CORE_FS_MGR_PRIV_H */ diff --git a/fs_mgr/fs_mgr_slotselect.c b/fs_mgr/fs_mgr_slotselect.c new file mode 100644 index 000000000..99dcd0e53 --- /dev/null +++ b/fs_mgr/fs_mgr_slotselect.c @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "fs_mgr.h" +#include "fs_mgr_priv.h" + +#include "bootloader.h" + +// Copies slot_suffix from misc into |out_suffix|. Returns 0 on +// success, -1 on error or if there is no non-empty slot_suffix. +static int get_active_slot_suffix_from_misc(struct fstab *fstab, + char *out_suffix, + size_t suffix_len) +{ + int n; + int misc_fd; + ssize_t num_read; + struct bootloader_message msg; + + misc_fd = -1; + for (n = 0; n < fstab->num_entries; n++) { + if (strcmp(fstab->recs[n].mount_point, "/misc") == 0) { + misc_fd = open(fstab->recs[n].blk_device, O_RDONLY); + if (misc_fd == -1) { + ERROR("Error opening misc partition \"%s\" (%s)\n", + fstab->recs[n].blk_device, + strerror(errno)); + return -1; + } else { + break; + } + } + } + + if (misc_fd == -1) { + ERROR("Error finding misc partition\n"); + return -1; + } + + num_read = TEMP_FAILURE_RETRY(read(misc_fd, &msg, sizeof(msg))); + // Linux will never return partial reads when reading from block + // devices so no need to worry about them. + if (num_read != sizeof(msg)) { + ERROR("Error reading bootloader_message (%s)\n", strerror(errno)); + close(misc_fd); + return -1; + } + close(misc_fd); + if (msg.slot_suffix[0] == '\0') + return -1; + strncpy(out_suffix, msg.slot_suffix, suffix_len); + return 0; +} + +// Gets slot_suffix from either the kernel cmdline / firmware, the +// misc partition or built-in fallback. +static void get_active_slot_suffix(struct fstab *fstab, char *out_suffix, + size_t suffix_len) +{ + char propbuf[PROPERTY_VALUE_MAX]; + + // Get the suffix from the kernel commandline (note that we don't + // allow the empty suffix). On bootloaders natively supporting A/B + // we'll hit this path every time so don't bother logging it. + property_get("ro.boot.slot_suffix", propbuf, ""); + if (propbuf[0] != '\0') { + strncpy(out_suffix, propbuf, suffix_len); + return; + } + + // If we couldn't get the suffix from the kernel cmdline, try the + // the misc partition. + if (get_active_slot_suffix_from_misc(fstab, out_suffix, suffix_len) == 0) { + INFO("Using slot suffix \"%s\" from misc\n", out_suffix); + return; + } + + // If that didn't work, fall back to _a. The reasoning here is + // that since the fstab has the slotselect option set (otherwise + // we wouldn't end up here) we must assume that partitions are + // indeed set up for A/B. This corner-case is important because we + // may be on this codepath on newly provisioned A/B devices where + // misc isn't set up properly (it's just zeroes) and the + // bootloader does not (yet) natively support A/B. + // + // Why '_a'? Because that's what system/extras/boot_control_copy + // is using and since the bootloader isn't A/B aware we assume + // slots are set up this way. + WARNING("Could not determine slot suffix, falling back to \"_a\"\n"); + strncpy(out_suffix, "_a", suffix_len); + return; +} + +// Updates |fstab| for slot_suffix. Returns 0 on success, -1 on error. +int fs_mgr_update_for_slotselect(struct fstab *fstab) +{ + int n; + char suffix[PROPERTY_VALUE_MAX]; + int got_suffix = 0; + + for (n = 0; n < fstab->num_entries; n++) { + if (fstab->recs[n].fs_mgr_flags & MF_SLOTSELECT) { + char *tmp; + + if (!got_suffix) { + memset(suffix, '\0', sizeof(suffix)); + get_active_slot_suffix(fstab, suffix, sizeof(suffix) - 1); + got_suffix = 1; + } + + if (asprintf(&tmp, "%s%s", fstab->recs[n].blk_device, + suffix) > 0) { + free(fstab->recs[n].blk_device); + fstab->recs[n].blk_device = tmp; + } else { + return -1; + } + } + } + return 0; +}