fs_mgr: Use slot_suffix field from bootloader_message.
This will make fs_mgr look in the misc partition for the A/B suffix to
use if one of more fstab entries is using the slotselect option and the
bootloader doesn't specify the suffix.
Change-Id: I24233195f60dd352bf8e7ac32b0d95dcd3323156
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 08d0671..cf2965e 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -3,13 +3,14 @@
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.c fs_mgr_verity.c fs_mgr_fstab.c fs_mgr_slotselect.c
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 d77d41f..3379deb 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -20,8 +20,6 @@
#include <string.h>
#include <sys/mount.h>
-#include <cutils/properties.h>
-
#include "fs_mgr_priv.h"
struct fs_mgr_flag_values {
@@ -310,25 +308,12 @@
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 cc02bac..992b544 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -82,6 +82,7 @@
#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 0000000..99dcd0e
--- /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 <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cutils/properties.h>
+
+#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;
+}