aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Ferguson <ferguson.david@gmail.com>2012-08-16 17:50:50 -0400
committerDavid Ferguson <ferguson.david@gmail.com>2012-08-16 21:00:28 -0400
commit80da17ec432d433362763df1a775e7b62c5c795a (patch)
tree747039465c275a707737614e9e46296d9c81e9b8
parent014d02059c8533f7e1b2ff3f1e8fdb5464098c59 (diff)
downloadbootable_recovery-80da17ec432d433362763df1a775e7b62c5c795a.zip
bootable_recovery-80da17ec432d433362763df1a775e7b62c5c795a.tar.gz
bootable_recovery-80da17ec432d433362763df1a775e7b62c5c795a.tar.bz2
recovery: support for more than 1 sdcard in USB mass storage
* Attempts to share any device behind /sdcard, /emmc, and /external_sd (in that order) * New option in recovery.fstab: lun=<path to LUN file> - specifies path to LUN file for given mount point - used when sharing a device over USB mass storage - restriction: only applicable to /sdcard, /emmc and /external_sd * If not specified in recovery.fstab, searches for available LUN files in order: 1. BOARD_UMS_LUNFILE (if defined) 2. /sys/devices/platform/usb_mass_storage/lun%d/file 3. /sys/class/android_usb/android0/f_mass_storage/lun/file 4. /sys/class/android_usb/android0/f_mass_storage/lun_ex/file ** More can be added to this list for better auto detection * Searches for available LUN files using %d replacement - %d is expanded to 0 and 1 only Change-Id: I09e91f9b6c1e2c5e96df8983b1132deeec6395b5
-rw-r--r--common.h3
-rw-r--r--extendedcommands.c156
-rw-r--r--roots.c4
3 files changed, 140 insertions, 23 deletions
diff --git a/common.h b/common.h
index 0232ba3..b203362 100644
--- a/common.h
+++ b/common.h
@@ -131,6 +131,9 @@ typedef struct {
const char* fs_options;
const char* fs_options2;
+
+ const char* lun; // (/sdcard, /emmc, /external_sd only) LUN file to
+ // use when mounting via USB mass storage
} Volume;
typedef struct {
diff --git a/extendedcommands.c b/extendedcommands.c
index 451eb17..47bdcee 100644
--- a/extendedcommands.c
+++ b/extendedcommands.c
@@ -430,25 +430,144 @@ void show_nandroid_delete_menu(const char* path)
}
}
-#ifndef BOARD_UMS_LUNFILE
-#define BOARD_UMS_LUNFILE "/sys/devices/platform/usb_mass_storage/lun0/file"
-#endif
+#define MAX_NUM_USB_VOLUMES 3
+#define LUN_FILE_EXPANDS 2
-void show_mount_usb_storage_menu()
-{
+struct lun_node {
+ const char *lun_file;
+ struct lun_node *next;
+};
+
+static struct lun_node *lun_head = NULL;
+static struct lun_node *lun_tail = NULL;
+
+int control_usb_storage_set_lun(Volume* vol, bool enable, const char *lun_file) {
+ char c = 0;
+ const char *vol_device = enable ? vol->device : &c;
int fd;
- Volume *vol = volume_for_path("/sdcard");
- if ((fd = open(BOARD_UMS_LUNFILE, O_WRONLY)) < 0) {
- LOGE("Unable to open ums lunfile (%s)", strerror(errno));
+ struct lun_node *node;
+
+ // Verify that we have not already used this LUN file
+ for(node = lun_head; node; node = node->next) {
+ if (!strcmp(node->lun_file, lun_file)) {
+ // Skip any LUN files that are already in use
+ return -1;
+ }
+ }
+
+ // Open a handle to the LUN file
+ LOGI("Trying %s on LUN file %s\n", vol->device, lun_file);
+ if ((fd = open(lun_file, O_WRONLY)) < 0) {
+ LOGW("Unable to open ums lunfile %s (%s)\n", lun_file, strerror(errno));
return -1;
}
- if ((write(fd, vol->device, strlen(vol->device)) < 0) &&
- (!vol->device2 || (write(fd, vol->device, strlen(vol->device2)) < 0))) {
- LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
+ // Write the volume path to the LUN file
+ if ((write(fd, vol_device, strlen(vol_device)) < 0) &&
+ (!enable || !vol->device2 || (write(fd, vol->device2, strlen(vol->device2)) < 0))) {
+ LOGW("Unable to write to ums lunfile %s (%s)\n", lun_file, strerror(errno));
close(fd);
return -1;
+ } else {
+ // Volume path to LUN association succeeded
+ close(fd);
+
+ // Save off a record of this lun_file being in use now
+ node = (struct lun_node *)malloc(sizeof(struct lun_node));
+ node->lun_file = strdup(lun_file);
+ node->next = NULL;
+ if (lun_head == NULL)
+ lun_head = lun_tail = node;
+ else {
+ lun_tail->next = node;
+ lun_tail = node;
+ }
+
+ LOGI("Successfully %sshared %s on LUN file %s\n", enable ? "" : "un", vol->device, lun_file);
+ return 0;
+ }
+}
+
+int control_usb_storage_for_lun(Volume* vol, bool enable) {
+ static const char* lun_files[] = {
+#ifdef BOARD_UMS_LUNFILE
+ BOARD_UMS_LUNFILE,
+#endif
+ "/sys/devices/platform/usb_mass_storage/lun%d/file",
+ "/sys/class/android_usb/android0/f_mass_storage/lun/file",
+ "/sys/class/android_usb/android0/f_mass_storage/lun_ex/file",
+ NULL
+ };
+
+ // If recovery.fstab specifies a LUN file, use it
+ if (vol->lun) {
+ return control_usb_storage_set_lun(vol, enable, vol->lun);
+ }
+
+ // Try to find a LUN for this volume
+ // - iterate through the lun file paths
+ // - expand any %d by LUN_FILE_EXPANDS
+ int lun_num = 0;
+ int i;
+ for(i = 0; lun_files[i]; i++) {
+ const char *lun_file = lun_files[i];
+ for(lun_num = 0; lun_num < LUN_FILE_EXPANDS; lun_num++) {
+ char formatted_lun_file[255];
+
+ // Replace %d with the LUN number
+ bzero(formatted_lun_file, 255);
+ snprintf(formatted_lun_file, 254, lun_file, lun_num);
+
+ // Attempt to use the LUN file
+ if (control_usb_storage_set_lun(vol, enable, formatted_lun_file) == 0) {
+ return 0;
+ }
+ }
+ }
+
+ // All LUNs were exhausted and none worked
+ LOGW("Could not %sable %s on LUN %d\n", enable ? "en" : "dis", vol->device, lun_num);
+
+ return -1; // -1 failure, 0 success
+}
+
+int control_usb_storage(Volume **volumes, bool enable) {
+ int res = -1;
+ int i;
+ for(i = 0; i < MAX_NUM_USB_VOLUMES; i++) {
+ Volume *volume = volumes[i];
+ if (volume) {
+ int vol_res = control_usb_storage_for_lun(volume, enable);
+ if (vol_res == 0) res = 0; // if any one path succeeds, we return success
+ }
+ }
+
+ // Release memory used by the LUN file linked list
+ struct lun_node *node = lun_head;
+ while(node) {
+ struct lun_node *next = node->next;
+ free((void *)node->lun_file);
+ free(node);
+ node = next;
}
+ lun_head = lun_tail = NULL;
+
+ return res; // -1 failure, 0 success
+}
+
+void show_mount_usb_storage_menu()
+{
+ // Build a list of Volume objects; some or all may not be valid
+ Volume* volumes[MAX_NUM_USB_VOLUMES] = {
+ volume_for_path("/sdcard"),
+ volume_for_path("/emmc"),
+ volume_for_path("/external_sd")
+ };
+
+ // Enable USB storage
+ if (control_usb_storage(volumes, 1))
+ return;
+
static char* headers[] = { "USB Mass Storage device",
"Leaving this menu unmount",
"your SD card from your PC.",
@@ -465,17 +584,8 @@ void show_mount_usb_storage_menu()
break;
}
- if ((fd = open(BOARD_UMS_LUNFILE, O_WRONLY)) < 0) {
- LOGE("Unable to open ums lunfile (%s)", strerror(errno));
- return -1;
- }
-
- char ch = 0;
- if (write(fd, &ch, 1) < 0) {
- LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
- close(fd);
- return -1;
- }
+ // Disable USB storage
+ control_usb_storage(volumes, 0);
}
int confirm_selection(const char* title, const char* confirm)
@@ -1435,4 +1545,4 @@ int verify_root_and_recovery() {
ensure_path_unmounted("/system");
return ret;
-} \ No newline at end of file
+}
diff --git a/roots.c b/roots.c
index dc9bbb1..d3dafcd 100644
--- a/roots.c
+++ b/roots.c
@@ -70,6 +70,8 @@ static int parse_options(char* options, Volume* volume) {
volume->fs_options = strdup(option + 11);
} else if (strncmp(option, "fs_options2=", 12) == 0) {
volume->fs_options2 = strdup(option + 12);
+ } else if (strncmp(option, "lun=", 4) == 0) {
+ volume->lun = strdup(option + 4);
} else {
LOGE("bad option \"%s\"\n", option);
return -1;
@@ -90,6 +92,7 @@ void load_volume_table() {
device_volumes[0].fs_type2 = NULL;
device_volumes[0].fs_options = NULL;
device_volumes[0].fs_options2 = NULL;
+ device_volumes[0].lun = NULL;
device_volumes[0].length = 0;
num_volumes = 1;
@@ -139,6 +142,7 @@ void load_volume_table() {
device_volumes[num_volumes].fs_type2 = NULL;
device_volumes[num_volumes].fs_options = NULL;
device_volumes[num_volumes].fs_options2 = NULL;
+ device_volumes[num_volumes].lun = NULL;
if (parse_options(options, device_volumes + num_volumes) != 0) {
LOGE("skipping malformed recovery.fstab line: %s\n", original);