fs.cpp 7.3 KB

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