Merge "init: use libbootloader_message." into nyc-mr1-dev
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 142a5e8..a821ddc 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -49,6 +49,7 @@
#include <android-base/parseint.h>
#include <android-base/parsenetaddress.h>
+#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <sparse/sparse.h>
#include <ziparchive/zip_archive.h>
@@ -101,25 +102,39 @@
static struct {
char img_name[17];
char sig_name[17];
- char item_name[17];
char part_name[9];
- bool active_slot;
bool is_optional;
+ bool is_secondary;
} images[] = {
- {"boot.img", "boot.sig", "boot", "boot", true, false},
- {"boot_other.img", "boot_other.sig", "boot_other", "boot", false, true},
- {"recovery.img", "recovery.sig", "recovery", "recovery", true, true},
- {"system.img", "system.sig", "system", "system", true, false},
- {"system_other.img", "system_other.sig", "system_other", "system", false, true},
- {"vendor.img", "vendor.sig", "vendor", "vendor", true, true},
- {"vendor_other.img", "vendor_other.sig", "vendor_other", "vendor", false, true},
+ {"boot.img", "boot.sig", "boot", false, false},
+ {"boot_other.img", "boot.sig", "boot", true, true},
+ {"recovery.img", "recovery.sig", "recovery", true, false},
+ {"system.img", "system.sig", "system", false, false},
+ {"system_other.img", "system.sig", "system", true, true},
+ {"vendor.img", "vendor.sig", "vendor", true, false},
+ {"vendor_other.img", "vendor.sig", "vendor", true, true},
};
-static char* find_item(const char* item, const char* product) {
+static std::string find_item_given_name(const char* img_name, const char* product) {
char *dir;
- const char *fn;
char path[PATH_MAX + 128];
+ if(product) {
+ get_my_path(path);
+ return android::base::StringPrintf("../../../target/product/%s/%s", product, img_name);
+ }
+
+ dir = getenv("ANDROID_PRODUCT_OUT");
+ if((dir == 0) || (dir[0] == 0)) {
+ die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
+ }
+
+ return android::base::StringPrintf("%s/%s", dir, img_name);
+}
+
+std::string find_item(const char* item, const char* product) {
+ const char *fn;
+
if(!strcmp(item,"boot")) {
fn = "boot.img";
} else if(!strcmp(item,"recovery")) {
@@ -134,32 +149,12 @@
fn = "cache.img";
} else if(!strcmp(item,"info")) {
fn = "android-info.txt";
- } else if(!strcmp(item,"system_other")) {
- fn = "system_other.img";
- } else if(!strcmp(item,"boot_other")) {
- fn = "boot_other.img";
- } else if(!strcmp(item,"vendor_other")) {
- fn = "vendor_other.img";
} else {
fprintf(stderr,"unknown partition '%s'\n", item);
- return 0;
+ return "";
}
- if(product) {
- get_my_path(path);
- sprintf(path + strlen(path),
- "../../../target/product/%s/%s", product, fn);
- return strdup(path);
- }
-
- dir = getenv("ANDROID_PRODUCT_OUT");
- if((dir == 0) || (dir[0] == 0)) {
- die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
- return 0;
- }
-
- sprintf(path, "%s/%s", dir, fn);
- return strdup(path);
+ return find_item_given_name(fn, product);
}
static int64_t get_file_size(int fd) {
@@ -325,8 +320,16 @@
"\n"
"commands:\n"
" update <filename> Reflash device from update.zip.\n"
+ " Sets the flashed slot as active.\n"
" flashall Flash boot, system, vendor, and --\n"
- " if found -- recovery.\n"
+ " if found -- recovery. If the device\n"
+ " supports slots, the slot that has\n"
+ " been flashed to is set as active.\n"
+ " Secondary images may be flashed to\n"
+ " an inactive slot.\n"
+ " flash-primary Same as flashall, but do not flash\n"
+ " secondary images.\n"
+ " flash-secondary Only flashes the secondary images.\n"
" flash <partition> [ <filename> ] Write a file to a flash partition.\n"
" flashing lock Locks the device. Prevents flashing.\n"
" flashing unlock Unlocks the device. Allows flashing\n"
@@ -391,10 +394,9 @@
" added to all partition names that use\n"
" slots. 'all' can be given to refer\n"
" to all slots. 'other' can be given to\n"
- " refer to a non-current slot. 'active' can\n"
- " be given to refer to a current slot only.\n"
- " If this flag is not given slots will be\n"
- " written to based on the filename.\n"
+ " refer to a non-current slot. If this\n"
+ " flag is not used, slotted partitions\n"
+ " will default to the current active slot.\n"
" -a, --set-active[=<suffix>] Sets the active slot. If no suffix is\n"
" provided, this will default to the value\n"
" given by --slot. If slots are not\n"
@@ -860,42 +862,46 @@
}
}
-static bool has_slots(Transport* transport) {
- std::string suffix_list_unused;
- return fb_getvar(transport, "slot-suffixes", &suffix_list_unused);
-}
-
static std::vector<std::string> get_suffixes(Transport* transport) {
std::vector<std::string> suffixes;
std::string suffix_list;
if (!fb_getvar(transport, "slot-suffixes", &suffix_list)) {
- die("Could not get suffixes.\n");
+ return suffixes;
}
- return android::base::Split(suffix_list, ",");
+ suffixes = android::base::Split(suffix_list, ",");
+ // Unfortunately some devices will return an error message in the
+ // guise of a valid value. If we only see only one suffix, it's probably
+ // not real.
+ if (suffixes.size() == 1) {
+ suffixes.clear();
+ }
+ return suffixes;
}
-// Returns a std::string of the slot name 'active_offset' after the active slot
-static std::string get_slot_name(Transport* transport, size_t active_offset) {
+static bool supports_AB(Transport* transport) {
+ return !get_suffixes(transport).empty();
+}
+
+// Given a current slot, this returns what the 'other' slot is.
+static std::string get_other_slot(Transport* transport, const std::string& current_slot) {
std::vector<std::string> suffixes = get_suffixes(transport);
- std::string current_slot;
- if (!fb_getvar(transport, "current-slot", ¤t_slot)) {
- die("Failed to identify current slot.");
- }
- if (active_offset >= suffixes.size()) {
- die("active slot offset larger than total number of slots!");
- }
+
if (!suffixes.empty()) {
for (size_t i = 0; i < suffixes.size(); i++) {
- if (current_slot == suffixes[i])
- return suffixes[(i + active_offset) % suffixes.size()];
+ if (current_slot == suffixes[i]) {
+ return suffixes[(i+1)%suffixes.size()];
+ }
}
- } else {
- die("No known slots.");
}
- die("Unable to find current slot");
return "";
}
+static std::string get_other_slot(Transport* transport) {
+ std::string current_slot;
+ fb_getvar(transport, "current-slot", ¤t_slot);
+ return get_other_slot(transport, current_slot);
+}
+
static std::string verify_slot(Transport* transport, const char *slot, bool allow_all) {
if (strcmp(slot, "all") == 0) {
if (allow_all) {
@@ -913,18 +919,28 @@
std::vector<std::string> suffixes = get_suffixes(transport);
if (strcmp(slot, "other") == 0) {
- return get_slot_name(transport, 1);
- } else if (strcmp(slot, "active") == 0) {
- return get_slot_name(transport, 0);
+ std::string current_slot;
+ if (!fb_getvar(transport, "current-slot", ¤t_slot)) {
+ die("Failed to identify current slot.");
+ }
+ std::string other = get_other_slot(transport, current_slot);
+ if (other == "") {
+ die("No known slots.");
+ }
+ return other;
}
for (const std::string &suffix : suffixes) {
if (suffix == slot)
return slot;
}
- fprintf(stderr, "Slot %s does not exist. supported slots are:\n", slot);
- for (const std::string &suffix : suffixes) {
- fprintf(stderr, "%s\n", suffix.c_str());
+ if (suffixes.empty()) {
+ fprintf(stderr, "Device does not support slots.\n");
+ } else {
+ fprintf(stderr, "Slot %s does not exist. supported slots are:\n", slot);
+ for (const std::string &suffix : suffixes) {
+ fprintf(stderr, "%s\n", suffix.c_str());
+ }
}
exit(1);
}
@@ -975,6 +991,9 @@
}
if (has_slot == "yes") {
std::vector<std::string> suffixes = get_suffixes(transport);
+ if (suffixes.empty()) {
+ die("Error reading suffixes.\n");
+ }
for (std::string &suffix : suffixes) {
do_for_partition(transport, part, suffix.c_str(), func, force_slot);
}
@@ -1003,7 +1022,23 @@
fb_queue_command("signature", "installing signature");
}
-static void do_update(Transport* transport, const char* filename, const char* slot_override, bool erase_first) {
+// Sets slot_override as the active slot. If slot_override is blank,
+// set current slot as active instead. This clears slot-unbootable.
+static void set_active(Transport* transport, const std::string& slot_override) {
+ if (!supports_AB(transport)) {
+ return;
+ } else if (slot_override != "") {
+ fb_set_active(slot_override.c_str());
+ } else {
+ std::string current_slot;
+ if (fb_getvar(transport, "current-slot", ¤t_slot)) {
+ current_slot = verify_slot(transport, current_slot.c_str(), false);
+ fb_set_active(current_slot.c_str());
+ }
+ }
+}
+
+static void do_update(Transport* transport, const char* filename, const std::string& slot_override, bool erase_first) {
queue_info_dump();
fb_queue_query_save("product", cur_product, sizeof(cur_product));
@@ -1024,7 +1059,31 @@
setup_requirements(reinterpret_cast<char*>(data), sz);
+ std::string secondary;
+ bool update_secondary = slot_override != "all";
+ if (update_secondary) {
+ if (slot_override != "") {
+ secondary = get_other_slot(transport, slot_override);
+ } else {
+ secondary = get_other_slot(transport);
+ }
+ if (secondary == "") {
+ if (supports_AB(transport)) {
+ fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n");
+ }
+ update_secondary = false;
+ }
+ }
for (size_t i = 0; i < ARRAY_SIZE(images); ++i) {
+ const char* slot = slot_override.c_str();
+ if (images[i].is_secondary) {
+ if (update_secondary) {
+ slot = secondary.c_str();
+ } else {
+ continue;
+ }
+ }
+
int fd = unzip_to_file(zip, images[i].img_name);
if (fd == -1) {
if (images[i].is_optional) {
@@ -1048,65 +1107,70 @@
* program exits.
*/
};
- do_for_partitions(transport, images[i].part_name, slot_override, update, false);
+ do_for_partitions(transport, images[i].part_name, slot, update, false);
}
CloseArchive(zip);
+ set_active(transport, slot_override);
}
-static void do_send_signature(char* fn) {
- char* xtn = strrchr(fn, '.');
- if (!xtn) return;
+static void do_send_signature(const std::string& fn) {
+ std::size_t extension_loc = fn.find(".img");
+ if (extension_loc == std::string::npos) return;
- if (strcmp(xtn, ".img")) return;
-
- strcpy(xtn, ".sig");
+ std::string fs_sig = fn.substr(0, extension_loc) + ".sig";
int64_t sz;
- void* data = load_file(fn, &sz);
- strcpy(xtn, ".img");
+ void* data = load_file(fs_sig.c_str(), &sz);
if (data == nullptr) return;
fb_queue_download("signature", data, sz);
fb_queue_command("signature", "installing signature");
}
-static void do_flashall(Transport* transport, const char* slot_override, int erase_first) {
- queue_info_dump();
- const bool device_has_slots = has_slots(transport);
- const bool has_slot_override = slot_override != nullptr && strcmp(slot_override, "") != 0;
- const bool should_ignore_slots = !device_has_slots || has_slot_override;
+static void do_flashall(Transport* transport, const std::string& slot_override, int erase_first, bool flash_primary, bool flash_secondary) {
+ std::string fname;
+ if (flash_primary) {
+ queue_info_dump();
- fb_queue_query_save("product", cur_product, sizeof(cur_product));
+ fb_queue_query_save("product", cur_product, sizeof(cur_product));
- char* fname = find_item("info", product);
- if (fname == nullptr) die("cannot find android-info.txt");
+ fname = find_item("info", product);
+ if (fname == "") die("cannot find android-info.txt");
- int64_t sz;
- void* data = load_file(fname, &sz);
- if (data == nullptr) die("could not load android-info.txt: %s", strerror(errno));
+ int64_t sz;
+ void* data = load_file(fname.c_str(), &sz);
+ if (data == nullptr) die("could not load android-info.txt: %s", strerror(errno));
- setup_requirements(reinterpret_cast<char*>(data), sz);
+ setup_requirements(reinterpret_cast<char*>(data), sz);
+ }
+ std::string secondary;
+ if (flash_secondary) {
+ if (slot_override != "") {
+ secondary = get_other_slot(transport, slot_override);
+ } else {
+ secondary = get_other_slot(transport);
+ }
+ if (secondary == "") {
+ if (supports_AB(transport)) {
+ fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.\n");
+ }
+ flash_secondary = false;
+ }
+ }
for (size_t i = 0; i < ARRAY_SIZE(images); i++) {
- if (should_ignore_slots && !images[i].active_slot) {
- // We will not do anything with _other files if we are given an explicit slot to use.
- continue;
- }
- fname = find_item(images[i].item_name, product);
- fastboot_buffer buf;
- if (load_buf(transport, fname, &buf)) {
- if (images[i].is_optional)
- continue;
- die("could not load %s\n", images[i].img_name);
- }
- // Get the actual slot we are writing to based on the filename. This is because we need to
- // sometimes write the 'active + 1'th slot for first boot optimization reasons. This is
- // defined by the images array unless one is explicitly provided.
- std::string real_slot_override;
- if (should_ignore_slots) {
- real_slot_override = slot_override;
+ const char* slot = NULL;
+ if (images[i].is_secondary) {
+ if (flash_secondary) slot = secondary.c_str();
} else {
- real_slot_override = get_slot_name(transport, images[i].active_slot ? 0 : 1);
+ if (flash_primary) slot = slot_override.c_str();
+ }
+ if (!slot) continue;
+ fname = find_item_given_name(images[i].img_name, product);
+ fastboot_buffer buf;
+ if (load_buf(transport, fname.c_str(), &buf)) {
+ if (images[i].is_optional) continue;
+ die("could not load %s\n", images[i].img_name);
}
auto flashall = [&](const std::string &partition) {
@@ -1116,12 +1180,10 @@
}
flash_buf(partition.c_str(), &buf);
};
- do_for_partitions(transport,
- images[i].part_name,
- real_slot_override.c_str(),
- flashall,
- false);
+ do_for_partitions(transport, images[i].part_name, slot, flashall, false);
}
+
+ if (flash_primary) set_active(transport, slot_override);
}
#define skip(n) do { argc -= (n); argv += (n); } while (0)
@@ -1448,15 +1510,18 @@
return 1;
}
- if (slot_override != "")
- slot_override = verify_slot(transport, slot_override.c_str());
- if (next_active != "")
- next_active = verify_slot(transport, next_active.c_str(), false);
+ if (slot_override != "") slot_override = verify_slot(transport, slot_override.c_str());
+ if (next_active != "") next_active = verify_slot(transport, next_active.c_str(), false);
if (wants_set_active) {
if (next_active == "") {
if (slot_override == "") {
- wants_set_active = false;
+ std::string current_slot;
+ if (fb_getvar(transport, "current-slot", ¤t_slot)) {
+ next_active = verify_slot(transport, current_slot.c_str(), false);
+ } else {
+ wants_set_active = false;
+ }
} else {
next_active = verify_slot(transport, slot_override.c_str(), false);
}
@@ -1567,7 +1632,7 @@
fb_queue_command("boot", "booting");
} else if(!strcmp(*argv, "flash")) {
char *pname = argv[1];
- char *fname = 0;
+ std::string fname;
require(2);
if (argc > 2) {
fname = argv[2];
@@ -1576,13 +1641,13 @@
fname = find_item(pname, product);
skip(2);
}
- if (fname == 0) die("cannot determine image filename for '%s'", pname);
+ if (fname == "") die("cannot determine image filename for '%s'", pname);
auto flash = [&](const std::string &partition) {
if (erase_first && needs_erase(transport, partition.c_str())) {
fb_queue_erase(partition.c_str());
}
- do_flash(transport, partition.c_str(), fname);
+ do_flash(transport, partition.c_str(), fname.c_str());
};
do_for_partitions(transport, pname, slot_override.c_str(), flash, true);
} else if(!strcmp(*argv, "flash:raw")) {
@@ -1607,14 +1672,27 @@
do_for_partitions(transport, argv[1], slot_override.c_str(), flashraw, true);
} else if(!strcmp(*argv, "flashall")) {
skip(1);
- do_flashall(transport, slot_override.c_str(), erase_first);
+ if (slot_override == "all") {
+ fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.");
+ do_flashall(transport, slot_override, erase_first, true, false);
+ } else {
+ do_flashall(transport, slot_override, erase_first, true, true);
+ }
+ wants_reboot = true;
+ } else if(!strcmp(*argv, "flash-primary")) {
+ skip(1);
+ do_flashall(transport, slot_override, erase_first, true, false);
+ wants_reboot = true;
+ } else if(!strcmp(*argv, "flash-secondary")) {
+ skip(1);
+ do_flashall(transport, slot_override, erase_first, false, true);
wants_reboot = true;
} else if(!strcmp(*argv, "update")) {
if (argc > 1) {
- do_update(transport, argv[1], slot_override.c_str(), erase_first);
+ do_update(transport, argv[1], slot_override, erase_first);
skip(2);
} else {
- do_update(transport, "update.zip", slot_override.c_str(), erase_first);
+ do_update(transport, "update.zip", slot_override, erase_first);
skip(1);
}
wants_reboot = 1;
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 5d512ae..5631877 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -345,6 +345,11 @@
return 0;
}
+/* umount <path> */
+static int do_umount(const std::vector<std::string>& args) {
+ return umount(args[1].c_str());
+}
+
static struct {
const char *name;
unsigned flag;
@@ -958,6 +963,7 @@
{"mkdir", {1, 4, do_mkdir}},
{"mount_all", {1, kMax, do_mount_all}},
{"mount", {3, kMax, do_mount}},
+ {"umount", {1, 1, do_umount}},
{"powerctl", {1, 1, do_powerctl}},
{"restart", {1, 1, do_restart}},
{"restorecon", {1, kMax, do_restorecon}},
diff --git a/init/readme.txt b/init/readme.txt
index ef85ccf..4481e24 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -355,6 +355,9 @@
Trigger an event. Used to queue an action from another
action.
+umount <path>
+ Unmount the filesystem mounted at that path.
+
verity_load_state
Internal implementation detail used to load dm-verity state.