diff options
author | David Ferguson <ferguson.david@gmail.com> | 2012-08-16 17:50:50 -0400 |
---|---|---|
committer | David Ferguson <ferguson.david@gmail.com> | 2012-08-16 21:00:28 -0400 |
commit | 80da17ec432d433362763df1a775e7b62c5c795a (patch) | |
tree | 747039465c275a707737614e9e46296d9c81e9b8 | |
parent | 014d02059c8533f7e1b2ff3f1e8fdb5464098c59 (diff) | |
download | bootable_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.h | 3 | ||||
-rw-r--r-- | extendedcommands.c | 156 | ||||
-rw-r--r-- | roots.c | 4 |
3 files changed, 140 insertions, 23 deletions
@@ -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 +} @@ -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); |