blob: f3c000eb78b677b3c84a2c6af6deb4a125c52ea6 [file] [log] [blame]
Paul Crowley8f7f56e2015-11-27 09:29:37 +00001#include "fs.h"
2
Dmitry Grinberge6f3e9b2014-03-11 18:28:15 -07003#include "fastboot.h"
JP Abgrall12351582014-06-17 17:01:14 -07004#include "make_f2fs.h"
Dmitry Grinberge6f3e9b2014-03-11 18:28:15 -07005
6#include <errno.h>
Jin Qian4a335822017-04-18 16:23:18 -07007#include <fcntl.h>
Dmitry Grinberge6f3e9b2014-03-11 18:28:15 -07008#include <stdio.h>
9#include <stdlib.h>
Dmitry Grinberge6f3e9b2014-03-11 18:28:15 -070010#include <string.h>
11#include <sys/stat.h>
12#include <sys/types.h>
Jin Qian4afba662017-04-18 18:19:12 -070013#ifndef WIN32
14#include <sys/wait.h>
15#endif
Dmitry Grinberge6f3e9b2014-03-11 18:28:15 -070016#include <unistd.h>
Jin Qian4afba662017-04-18 18:19:12 -070017#include <vector>
Dmitry Grinberge6f3e9b2014-03-11 18:28:15 -070018
Jin Qian4afba662017-04-18 18:19:12 -070019#include <android-base/file.h>
20#include <android-base/stringprintf.h>
Jin Qian4a335822017-04-18 16:23:18 -070021#include <android-base/unique_fd.h>
Tao Bao6d881d62016-10-05 17:53:30 -070022#include <ext4_utils/make_ext4fs.h>
Elliott Hughesfc797672015-04-07 20:12:50 -070023#include <sparse/sparse.h>
Dmitry Grinberge6f3e9b2014-03-11 18:28:15 -070024
Jin Qian4afba662017-04-18 18:19:12 -070025using android::base::StringPrintf;
Jin Qian4a335822017-04-18 16:23:18 -070026using android::base::unique_fd;
27
Jin Qian4afba662017-04-18 18:19:12 -070028#ifdef WIN32
Jin Qian4a335822017-04-18 16:23:18 -070029static int generate_ext4_image(const char* fileName, long long partSize, const std::string& initial_dir,
Connor O'Brience16a8a2017-02-06 14:39:31 -080030 unsigned eraseBlkSize, unsigned logicalBlkSize)
Dmitry Grinberge6f3e9b2014-03-11 18:28:15 -070031{
Jin Qian4a335822017-04-18 16:23:18 -070032 unique_fd fd(open(fileName, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR));
33 if (fd == -1) {
34 fprintf(stderr, "Unable to open output file for EXT4 filesystem: %s\n", strerror(errno));
35 return -1;
36 }
Paul Crowley8f7f56e2015-11-27 09:29:37 +000037 if (initial_dir.empty()) {
Connor O'Brience16a8a2017-02-06 14:39:31 -080038 make_ext4fs_sparse_fd_align(fd, partSize, NULL, NULL, eraseBlkSize, logicalBlkSize);
Paul Crowley8f7f56e2015-11-27 09:29:37 +000039 } else {
Connor O'Brience16a8a2017-02-06 14:39:31 -080040 make_ext4fs_sparse_fd_directory_align(fd, partSize, NULL, NULL, initial_dir.c_str(),
41 eraseBlkSize, logicalBlkSize);
Paul Crowley8f7f56e2015-11-27 09:29:37 +000042 }
Dmitry Grinberge6f3e9b2014-03-11 18:28:15 -070043 return 0;
44}
Jin Qian4afba662017-04-18 18:19:12 -070045#else
46static int exec_e2fs_cmd(const char* path, char* const argv[]) {
47 int status;
48 pid_t child;
49 if ((child = fork()) == 0) {
50 setenv("MKE2FS_CONFIG", "", 1);
51 execvp(path, argv);
52 _exit(EXIT_FAILURE);
53 }
54 if (child < 0) {
55 fprintf(stderr, "%s failed with fork %s\n", path, strerror(errno));
56 return -1;
57 }
58 if (TEMP_FAILURE_RETRY(waitpid(child, &status, 0)) == -1) {
59 fprintf(stderr, "%s failed with waitpid %s\n", path, strerror(errno));
60 return -1;
61 }
62 int ret = -1;
63 if (WIFEXITED(status)) {
64 ret = WEXITSTATUS(status);
65 if (ret != 0) {
66 fprintf(stderr, "%s failed with status %d\n", path, ret);
67 }
68 }
69 return ret;
70}
71
72static int generate_ext4_image(const char* fileName, long long partSize,
73 const std::string& initial_dir, unsigned eraseBlkSize,
74 unsigned logicalBlkSize) {
75 static constexpr int block_size = 4096;
76 const std::string exec_dir = android::base::GetExecutableDirectory();
77
78 const std::string mke2fs_path = exec_dir + "/mke2fs";
79 std::vector<const char*> mke2fs_args = {mke2fs_path.c_str(), "-t", "ext4", "-b"};
80
81 std::string block_size_str = std::to_string(block_size);
82 mke2fs_args.push_back(block_size_str.c_str());
83
84 std::string ext_attr = "android_sparse";
85 if (eraseBlkSize != 0 && logicalBlkSize != 0) {
86 int raid_stride = logicalBlkSize / block_size;
87 int raid_stripe_width = eraseBlkSize / block_size;
88 // stride should be the max of 8kb and logical block size
89 if (logicalBlkSize != 0 && logicalBlkSize < 8192) raid_stride = 8192 / block_size;
90 ext_attr += StringPrintf(",stride=%d,stripe-width=%d", raid_stride, raid_stripe_width);
91 }
92 mke2fs_args.push_back("-E");
93 mke2fs_args.push_back(ext_attr.c_str());
94 mke2fs_args.push_back(fileName);
95
96 std::string size_str = std::to_string(partSize / block_size);
97 mke2fs_args.push_back(size_str.c_str());
98 mke2fs_args.push_back(nullptr);
99
100 int ret = exec_e2fs_cmd(mke2fs_args[0], const_cast<char**>(mke2fs_args.data()));
101 if (ret != 0) {
102 fprintf(stderr, "mke2fs failed: %d\n", ret);
103 return -1;
104 }
105
106 if (initial_dir.empty()) {
107 return 0;
108 }
109
110 const std::string e2fsdroid_path = exec_dir + "/e2fsdroid";
111 std::vector<const char*> e2fsdroid_args = {e2fsdroid_path.c_str(), "-f", initial_dir.c_str(),
112 fileName, nullptr};
113
114 ret = exec_e2fs_cmd(e2fsdroid_args[0], const_cast<char**>(e2fsdroid_args.data()));
115 if (ret != 0) {
116 fprintf(stderr, "e2fsdroid failed: %d\n", ret);
117 return -1;
118 }
119
120 return 0;
121}
122#endif
Dmitry Grinberge6f3e9b2014-03-11 18:28:15 -0700123
JP Abgrall6bd72be2014-06-17 23:43:18 -0700124#ifdef USE_F2FS
Jin Qian4a335822017-04-18 16:23:18 -0700125static int generate_f2fs_image(const char* fileName, long long partSize, const std::string& initial_dir,
Connor O'Brience16a8a2017-02-06 14:39:31 -0800126 unsigned /* unused */, unsigned /* unused */)
JP Abgrall12351582014-06-17 17:01:14 -0700127{
Paul Crowley8f7f56e2015-11-27 09:29:37 +0000128 if (!initial_dir.empty()) {
Jin Qian4a335822017-04-18 16:23:18 -0700129 fprintf(stderr, "Unable to set initial directory on F2FS filesystem: %s\n", strerror(errno));
130 return -1;
131 }
132 unique_fd fd(open(fileName, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR));
133 if (fd == -1) {
134 fprintf(stderr, "Unable to open output file for F2FS filesystem: %s\n", strerror(errno));
Paul Crowley8f7f56e2015-11-27 09:29:37 +0000135 return -1;
136 }
JP Abgrall6bd72be2014-06-17 23:43:18 -0700137 return make_f2fs_sparse_fd(fd, partSize, NULL, NULL);
JP Abgrall12351582014-06-17 17:01:14 -0700138}
JP Abgrall6bd72be2014-06-17 23:43:18 -0700139#endif
JP Abgrall12351582014-06-17 17:01:14 -0700140
Dmitry Grinberge6f3e9b2014-03-11 18:28:15 -0700141static const struct fs_generator {
Elliott Hughesb3748de2015-06-23 20:27:58 -0700142 const char* fs_type; //must match what fastboot reports for partition type
Paul Crowley8f7f56e2015-11-27 09:29:37 +0000143
144 //returns 0 or error value
Jin Qian4a335822017-04-18 16:23:18 -0700145 int (*generate)(const char* fileName, long long partSize, const std::string& initial_dir,
Connor O'Brience16a8a2017-02-06 14:39:31 -0800146 unsigned eraseBlkSize, unsigned logicalBlkSize);
Dmitry Grinberge6f3e9b2014-03-11 18:28:15 -0700147
148} generators[] = {
JP Abgrall12351582014-06-17 17:01:14 -0700149 { "ext4", generate_ext4_image},
JP Abgrall6bd72be2014-06-17 23:43:18 -0700150#ifdef USE_F2FS
JP Abgrall12351582014-06-17 17:01:14 -0700151 { "f2fs", generate_f2fs_image},
JP Abgrall6bd72be2014-06-17 23:43:18 -0700152#endif
Dmitry Grinberge6f3e9b2014-03-11 18:28:15 -0700153};
154
Elliott Hughes8ab9a322015-11-02 14:05:57 -0800155const struct fs_generator* fs_get_generator(const std::string& fs_type) {
Elliott Hughesfc797672015-04-07 20:12:50 -0700156 for (size_t i = 0; i < sizeof(generators) / sizeof(*generators); i++) {
Elliott Hughes8ab9a322015-11-02 14:05:57 -0800157 if (fs_type == generators[i].fs_type) {
Dmitry Grinberge6f3e9b2014-03-11 18:28:15 -0700158 return generators + i;
Elliott Hughesfc797672015-04-07 20:12:50 -0700159 }
160 }
161 return nullptr;
Dmitry Grinberge6f3e9b2014-03-11 18:28:15 -0700162}
163
Jin Qian4a335822017-04-18 16:23:18 -0700164int fs_generator_generate(const struct fs_generator* gen, const char* fileName, long long partSize,
Connor O'Brience16a8a2017-02-06 14:39:31 -0800165 const std::string& initial_dir, unsigned eraseBlkSize, unsigned logicalBlkSize)
Dmitry Grinberge6f3e9b2014-03-11 18:28:15 -0700166{
Jin Qian4a335822017-04-18 16:23:18 -0700167 return gen->generate(fileName, partSize, initial_dir, eraseBlkSize, logicalBlkSize);
Dmitry Grinberge6f3e9b2014-03-11 18:28:15 -0700168}