/* * Copyright (C) 2008 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #define _LARGEFILE64_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bootimg_utils.h" #include "diagnose_usb.h" #include "fastboot.h" #include "fs.h" #include "tcp.h" #include "transport.h" #include "udp.h" #include "usb.h" #ifndef O_BINARY #define O_BINARY 0 #endif #define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a))) char cur_product[FB_RESPONSE_SZ + 1]; static const char* serial = nullptr; static const char* product = nullptr; static const char* cmdline = nullptr; static unsigned short vendor_id = 0; static int long_listing = 0; static int64_t sparse_limit = -1; static int64_t target_sparse_limit = -1; static unsigned page_size = 2048; static unsigned base_addr = 0x10000000; static unsigned kernel_offset = 0x00008000; static unsigned ramdisk_offset = 0x01000000; static unsigned second_offset = 0x00f00000; static unsigned tags_offset = 0x00000100; enum fb_buffer_type { FB_BUFFER, FB_BUFFER_SPARSE, }; struct fastboot_buffer { enum fb_buffer_type type; void* data; int64_t sz; }; static struct { char img_name[13]; char sig_name[13]; char part_name[9]; bool is_optional; } images[] = { {"boot.img", "boot.sig", "boot", false}, {"recovery.img", "recovery.sig", "recovery", true}, {"system.img", "system.sig", "system", false}, {"vendor.img", "vendor.sig", "vendor", true}, }; static 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")) { fn = "recovery.img"; } else if(!strcmp(item,"system")) { fn = "system.img"; } else if(!strcmp(item,"vendor")) { fn = "vendor.img"; } else if(!strcmp(item,"userdata")) { fn = "userdata.img"; } else if(!strcmp(item,"cache")) { fn = "cache.img"; } else if(!strcmp(item,"info")) { fn = "android-info.txt"; } else { fprintf(stderr,"unknown partition '%s'\n", item); return ""; } if (product) { std::string path = get_my_path(); path.erase(path.find_last_of('/')); return android::base::StringPrintf("%s/../../../target/product/%s/%s", path.c_str(), product, fn); } char* dir = getenv("ANDROID_PRODUCT_OUT"); if (dir == nullptr || dir[0] == '\0') { die("neither -p product specified nor ANDROID_PRODUCT_OUT set"); } return android::base::StringPrintf("%s/%s", dir, fn); } static int64_t get_file_size(int fd) { struct stat sb; return fstat(fd, &sb) == -1 ? -1 : sb.st_size; } static void* load_fd(int fd, int64_t* sz) { int errno_tmp; char* data = nullptr; *sz = get_file_size(fd); if (*sz < 0) { goto oops; } data = (char*) malloc(*sz); if (data == nullptr) goto oops; if(read(fd, data, *sz) != *sz) goto oops; close(fd); return data; oops: errno_tmp = errno; close(fd); if(data != 0) free(data); errno = errno_tmp; return 0; } static void* load_file(const std::string& path, int64_t* sz) { int fd = open(path.c_str(), O_RDONLY | O_BINARY); if (fd == -1) return nullptr; return load_fd(fd, sz); } static int match_fastboot_with_serial(usb_ifc_info* info, const char* local_serial) { // Require a matching vendor id if the user specified one with -i. if (vendor_id != 0 && info->dev_vendor != vendor_id) { return -1; } if (info->ifc_class != 0xff || info->ifc_subclass != 0x42 || info->ifc_protocol != 0x03) { return -1; } // require matching serial number or device path if requested // at the command line with the -s option. if (local_serial && (strcmp(local_serial, info->serial_number) != 0 && strcmp(local_serial, info->device_path) != 0)) return -1; return 0; } static int match_fastboot(usb_ifc_info* info) { return match_fastboot_with_serial(info, serial); } static int list_devices_callback(usb_ifc_info* info) { if (match_fastboot_with_serial(info, nullptr) == 0) { std::string serial = info->serial_number; if (!info->writable) { serial = UsbNoPermissionsShortHelpText(); } if (!serial[0]) { serial = "????????????"; } // output compatible with "adb devices" if (!long_listing) { printf("%s\tfastboot", serial.c_str()); } else { printf("%-22s fastboot", serial.c_str()); if (strlen(info->device_path) > 0) printf(" %s", info->device_path); } putchar('\n'); } return -1; } // Opens a new Transport connected to a device. If |serial| is non-null it will be used to identify // a specific device, otherwise the first USB device found will be used. // // If |serial| is non-null but invalid, this prints an error message to stderr and returns nullptr. // Otherwise it blocks until the target is available. // // The returned Transport is a singleton, so multiple calls to this function will return the same // object, and the caller should not attempt to delete the returned Transport. static Transport* open_device() { static Transport* transport = nullptr; bool announce = true; if (transport != nullptr) { return transport; } Socket::Protocol protocol = Socket::Protocol::kTcp; std::string host; int port = 0; if (serial != nullptr) { const char* net_address = nullptr; if (android::base::StartsWith(serial, "tcp:")) { protocol = Socket::Protocol::kTcp; port = tcp::kDefaultPort; net_address = serial + strlen("tcp:"); } else if (android::base::StartsWith(serial, "udp:")) { protocol = Socket::Protocol::kUdp; port = udp::kDefaultPort; net_address = serial + strlen("udp:"); } if (net_address != nullptr) { std::string error; if (!android::base::ParseNetAddress(net_address, &host, &port, nullptr, &error)) { fprintf(stderr, "error: Invalid network address '%s': %s\n", net_address, error.c_str()); return nullptr; } } } while (true) { if (!host.empty()) { std::string error; if (protocol == Socket::Protocol::kTcp) { transport = tcp::Connect(host, port, &error).release(); } else if (protocol == Socket::Protocol::kUdp) { transport = udp::Connect(host, port, &error).release(); } if (transport == nullptr && announce) { fprintf(stderr, "error: %s\n", error.c_str()); } } else { transport = usb_open(match_fastboot); } if (transport != nullptr) { return transport; } if (announce) { announce = false; fprintf(stderr, "< waiting for %s >\n", serial ? serial : "any device"); } usleep(1000); } } static void list_devices() { // We don't actually open a USB device here, // just getting our callback called so we can // list all the connected devices. usb_open(list_devices_callback); } static void usage() { fprintf(stderr, /* 1234567890123456789012345678901234567890123456789012345678901234567890123456 */ "usage: fastboot [