Home | History | Annotate | Download | only in fastboot
      1 #include "fs.h"
      2 
      3 #include "fastboot.h"
      4 
      5 #include <errno.h>
      6 #include <fcntl.h>
      7 #include <stdio.h>
      8 #include <stdlib.h>
      9 #include <string.h>
     10 #include <sys/stat.h>
     11 #include <sys/types.h>
     12 #ifndef WIN32
     13 #include <sys/wait.h>
     14 #else
     15 #include <tchar.h>
     16 #include <windows.h>
     17 #endif
     18 #include <unistd.h>
     19 #include <vector>
     20 
     21 #include <android-base/errors.h>
     22 #include <android-base/file.h>
     23 #include <android-base/stringprintf.h>
     24 #include <android-base/unique_fd.h>
     25 
     26 using android::base::GetExecutableDirectory;
     27 using android::base::StringPrintf;
     28 using android::base::unique_fd;
     29 
     30 #ifdef WIN32
     31 static int exec_cmd(const char* path, const char** argv, const char** envp) {
     32     std::string cmd;
     33     int i = 0;
     34     while (argv[i] != nullptr) {
     35         cmd += argv[i++];
     36         cmd += " ";
     37     }
     38     cmd = cmd.substr(0, cmd.size() - 1);
     39 
     40     STARTUPINFO si;
     41     PROCESS_INFORMATION pi;
     42     DWORD exit_code = 0;
     43 
     44     ZeroMemory(&si, sizeof(si));
     45     si.cb = sizeof(si);
     46     ZeroMemory(&pi, sizeof(pi));
     47 
     48     std::string env_str;
     49     if (envp != nullptr) {
     50         while (*envp != nullptr) {
     51             env_str += std::string(*envp) + std::string("\0", 1);
     52             envp++;
     53         }
     54     }
     55 
     56     if (!CreateProcessA(nullptr,                         // No module name (use command line)
     57                         const_cast<char*>(cmd.c_str()),  // Command line
     58                         nullptr,                         // Process handle not inheritable
     59                         nullptr,                         // Thread handle not inheritable
     60                         FALSE,                           // Set handle inheritance to FALSE
     61                         0,                               // No creation flags
     62                         env_str.empty() ? nullptr : LPSTR(env_str.c_str()),
     63                         nullptr,  // Use parent's starting directory
     64                         &si,      // Pointer to STARTUPINFO structure
     65                         &pi)      // Pointer to PROCESS_INFORMATION structure
     66     ) {
     67         fprintf(stderr, "CreateProcess failed: %s\n",
     68                 android::base::SystemErrorCodeToString(GetLastError()).c_str());
     69         return -1;
     70     }
     71 
     72     WaitForSingleObject(pi.hProcess, INFINITE);
     73 
     74     GetExitCodeProcess(pi.hProcess, &exit_code);
     75 
     76     CloseHandle(pi.hProcess);
     77     CloseHandle(pi.hThread);
     78 
     79     if (exit_code != 0) {
     80         fprintf(stderr, "%s failed: %lu\n", path, exit_code);
     81         return -1;
     82     }
     83     return 0;
     84 }
     85 #else
     86 static int exec_cmd(const char* path, const char** argv, const char** envp) {
     87     int status;
     88     pid_t child;
     89     if ((child = fork()) == 0) {
     90         execve(path, const_cast<char**>(argv), const_cast<char**>(envp));
     91         _exit(EXIT_FAILURE);
     92     }
     93     if (child < 0) {
     94         fprintf(stderr, "%s failed with fork %s\n", path, strerror(errno));
     95         return -1;
     96     }
     97     if (TEMP_FAILURE_RETRY(waitpid(child, &status, 0)) == -1) {
     98         fprintf(stderr, "%s failed with waitpid %s\n", path, strerror(errno));
     99         return -1;
    100     }
    101     int ret = -1;
    102     if (WIFEXITED(status)) {
    103         ret = WEXITSTATUS(status);
    104     }
    105 
    106     if (ret != 0) {
    107         fprintf(stderr, "%s failed with status %d\n", path, ret);
    108         return -1;
    109     }
    110     return 0;
    111 }
    112 #endif
    113 
    114 static int generate_ext4_image(const char* fileName, long long partSize,
    115                                const std::string& initial_dir, unsigned eraseBlkSize,
    116                                unsigned logicalBlkSize) {
    117     static constexpr int block_size = 4096;
    118     const std::string exec_dir = android::base::GetExecutableDirectory();
    119 
    120     const std::string mke2fs_path = exec_dir + "/mke2fs";
    121     std::vector<const char*> mke2fs_args = {mke2fs_path.c_str(), "-t", "ext4", "-b"};
    122 
    123     std::string block_size_str = std::to_string(block_size);
    124     mke2fs_args.push_back(block_size_str.c_str());
    125 
    126     std::string ext_attr = "android_sparse";
    127     if (eraseBlkSize != 0 && logicalBlkSize != 0) {
    128         int raid_stride = logicalBlkSize / block_size;
    129         int raid_stripe_width = eraseBlkSize / block_size;
    130         // stride should be the max of 8kb and logical block size
    131         if (logicalBlkSize != 0 && logicalBlkSize < 8192) raid_stride = 8192 / block_size;
    132         // stripe width should be >= stride
    133         if (raid_stripe_width < raid_stride) raid_stripe_width = raid_stride;
    134         ext_attr += StringPrintf(",stride=%d,stripe-width=%d", raid_stride, raid_stripe_width);
    135     }
    136     mke2fs_args.push_back("-E");
    137     mke2fs_args.push_back(ext_attr.c_str());
    138     mke2fs_args.push_back("-O");
    139     mke2fs_args.push_back("uninit_bg");
    140     mke2fs_args.push_back(fileName);
    141 
    142     std::string size_str = std::to_string(partSize / block_size);
    143     mke2fs_args.push_back(size_str.c_str());
    144     mke2fs_args.push_back(nullptr);
    145 
    146     const std::string mke2fs_env = "MKE2FS_CONFIG=" + GetExecutableDirectory() + "/mke2fs.conf";
    147     std::vector<const char*> mke2fs_envp = {mke2fs_env.c_str(), nullptr};
    148 
    149     int ret = exec_cmd(mke2fs_args[0], mke2fs_args.data(), mke2fs_envp.data());
    150     if (ret != 0) {
    151         return -1;
    152     }
    153 
    154     if (initial_dir.empty()) {
    155         return 0;
    156     }
    157 
    158     const std::string e2fsdroid_path = exec_dir + "/e2fsdroid";
    159     std::vector<const char*> e2fsdroid_args = {e2fsdroid_path.c_str(), "-f", initial_dir.c_str(),
    160                                                fileName, nullptr};
    161 
    162     return exec_cmd(e2fsdroid_args[0], e2fsdroid_args.data(), nullptr);
    163 }
    164 
    165 static int generate_f2fs_image(const char* fileName, long long partSize, const std::string& initial_dir,
    166                                unsigned /* unused */, unsigned /* unused */)
    167 {
    168     const std::string exec_dir = android::base::GetExecutableDirectory();
    169     const std::string mkf2fs_path = exec_dir + "/make_f2fs";
    170     std::vector<const char*> mkf2fs_args = {mkf2fs_path.c_str()};
    171 
    172     mkf2fs_args.push_back("-S");
    173     std::string size_str = std::to_string(partSize);
    174     mkf2fs_args.push_back(size_str.c_str());
    175     mkf2fs_args.push_back("-f");
    176     mkf2fs_args.push_back("-O");
    177     mkf2fs_args.push_back("encrypt");
    178     mkf2fs_args.push_back("-O");
    179     mkf2fs_args.push_back("quota");
    180     mkf2fs_args.push_back("-O");
    181     mkf2fs_args.push_back("verity");
    182     mkf2fs_args.push_back(fileName);
    183     mkf2fs_args.push_back(nullptr);
    184 
    185     int ret = exec_cmd(mkf2fs_args[0], mkf2fs_args.data(), nullptr);
    186     if (ret != 0) {
    187         return -1;
    188     }
    189 
    190     if (initial_dir.empty()) {
    191         return 0;
    192     }
    193 
    194     const std::string sload_path = exec_dir + "/sload_f2fs";
    195     std::vector<const char*> sload_args = {sload_path.c_str(), "-S",
    196                                        "-f", initial_dir.c_str(), fileName, nullptr};
    197 
    198     return exec_cmd(sload_args[0], sload_args.data(), nullptr);
    199 }
    200 
    201 static const struct fs_generator {
    202     const char* fs_type;  //must match what fastboot reports for partition type
    203 
    204     //returns 0 or error value
    205     int (*generate)(const char* fileName, long long partSize, const std::string& initial_dir,
    206                     unsigned eraseBlkSize, unsigned logicalBlkSize);
    207 
    208 } generators[] = {
    209     { "ext4", generate_ext4_image},
    210     { "f2fs", generate_f2fs_image},
    211 };
    212 
    213 const struct fs_generator* fs_get_generator(const std::string& fs_type) {
    214     for (size_t i = 0; i < sizeof(generators) / sizeof(*generators); i++) {
    215         if (fs_type == generators[i].fs_type) {
    216             return generators + i;
    217         }
    218     }
    219     return nullptr;
    220 }
    221 
    222 int fs_generator_generate(const struct fs_generator* gen, const char* fileName, long long partSize,
    223     const std::string& initial_dir, unsigned eraseBlkSize, unsigned logicalBlkSize)
    224 {
    225     return gen->generate(fileName, partSize, initial_dir, eraseBlkSize, logicalBlkSize);
    226 }
    227