blob: 46e5c1bc33f1b0e08f9dd63697acf34acf14e008 [file] [log] [blame]
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Elliott Hughes63a31922016-06-09 17:41:22 -070017#include "roots.h"
18
Tao Baobb10e582017-07-22 16:30:34 -070019#include <ctype.h>
20#include <fcntl.h>
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080021#include <stdlib.h>
22#include <sys/mount.h>
23#include <sys/stat.h>
24#include <sys/types.h>
JP Abgrall37aedb32014-06-16 19:07:39 -070025#include <sys/wait.h>
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080026#include <unistd.h>
27
Tianjie Xu7b0ad9c2016-08-05 18:00:04 -070028#include <android-base/logging.h>
Jin Qianded2dac2017-04-21 14:36:12 -070029#include <android-base/properties.h>
30#include <android-base/stringprintf.h>
Jin Qianf3ccad52017-07-24 10:34:35 -070031#include <android-base/unique_fd.h>
Tao Baobb10e582017-07-22 16:30:34 -070032#include <cryptfs.h>
Tao Baode40ba52016-10-05 23:17:01 -070033#include <ext4_utils/wipe.h>
Ken Sumrallf35d1ce2013-02-13 12:59:35 -080034#include <fs_mgr.h>
Tao Baode40ba52016-10-05 23:17:01 -070035
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080036#include "common.h"
Elliott Hughes63a31922016-06-09 17:41:22 -070037#include "mounts.h"
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080038
Tao Baobb10e582017-07-22 16:30:34 -070039static struct fstab* fstab = nullptr;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080040
Tao Baobb10e582017-07-22 16:30:34 -070041extern struct selabel_handle* sehandle;
Stephen Smalley779701d2012-02-09 14:13:23 -050042
Tao Baobb10e582017-07-22 16:30:34 -070043void load_volume_table() {
44 fstab = fs_mgr_read_fstab_default();
45 if (!fstab) {
46 LOG(ERROR) << "Failed to read default fstab";
47 return;
48 }
Doug Zongker2810ced2011-02-17 15:55:21 -080049
Tao Baobb10e582017-07-22 16:30:34 -070050 int ret = fs_mgr_add_entry(fstab, "/tmp", "ramdisk", "ramdisk");
51 if (ret == -1) {
52 LOG(ERROR) << "Failed to add /tmp entry to fstab";
53 fs_mgr_free_fstab(fstab);
54 fstab = nullptr;
55 return;
56 }
Doug Zongkerd4208f92010-09-20 12:16:13 -070057
Tao Baobb10e582017-07-22 16:30:34 -070058 printf("recovery filesystem table\n");
59 printf("=========================\n");
60 for (int i = 0; i < fstab->num_entries; ++i) {
61 const Volume* v = &fstab->recs[i];
62 printf(" %d %s %s %s %lld\n", i, v->mount_point, v->fs_type, v->blk_device, v->length);
63 }
64 printf("\n");
Doug Zongkerd4208f92010-09-20 12:16:13 -070065}
66
67Volume* volume_for_path(const char* path) {
Tao Baobb10e582017-07-22 16:30:34 -070068 return fs_mgr_get_entry_for_mount_point(fstab, path);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080069}
70
Tao Baoabb8f772015-07-30 14:43:27 -070071// Mount the volume specified by path at the given mount_point.
72int ensure_path_mounted_at(const char* path, const char* mount_point) {
Tao Baobb10e582017-07-22 16:30:34 -070073 Volume* v = volume_for_path(path);
74 if (v == nullptr) {
75 LOG(ERROR) << "unknown volume for path [" << path << "]";
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080076 return -1;
Tao Baobb10e582017-07-22 16:30:34 -070077 }
78 if (strcmp(v->fs_type, "ramdisk") == 0) {
79 // The ramdisk is always mounted.
80 return 0;
81 }
82
83 if (!scan_mounted_volumes()) {
84 LOG(ERROR) << "Failed to scan mounted volumes";
85 return -1;
86 }
87
88 if (!mount_point) {
89 mount_point = v->mount_point;
90 }
91
92 const MountedVolume* mv = find_mounted_volume_by_mount_point(mount_point);
93 if (mv != nullptr) {
94 // Volume is already mounted.
95 return 0;
96 }
97
98 mkdir(mount_point, 0755); // in case it doesn't already exist
99
100 if (strcmp(v->fs_type, "ext4") == 0 || strcmp(v->fs_type, "squashfs") == 0 ||
101 strcmp(v->fs_type, "vfat") == 0) {
102 int result = mount(v->blk_device, mount_point, v->fs_type, v->flags, v->fs_options);
103 if (result == -1 && fs_mgr_is_formattable(v)) {
104 PLOG(ERROR) << "Failed to mount " << mount_point << "; formatting";
105 bool crypt_footer = fs_mgr_is_encryptable(v) && !strcmp(v->key_loc, "footer");
106 if (fs_mgr_do_format(v, crypt_footer) == 0) {
107 result = mount(v->blk_device, mount_point, v->fs_type, v->flags, v->fs_options);
108 } else {
109 PLOG(ERROR) << "Failed to format " << mount_point;
110 return -1;
111 }
112 }
113
114 if (result == -1) {
115 PLOG(ERROR) << "Failed to mount " << mount_point;
116 return -1;
117 }
118 return 0;
119 }
120
121 LOG(ERROR) << "unknown fs_type \"" << v->fs_type << "\" for " << mount_point;
122 return -1;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800123}
124
Tao Baoabb8f772015-07-30 14:43:27 -0700125int ensure_path_mounted(const char* path) {
Tao Baobb10e582017-07-22 16:30:34 -0700126 // Mount at the default mount point.
127 return ensure_path_mounted_at(path, nullptr);
Tao Baoabb8f772015-07-30 14:43:27 -0700128}
129
Doug Zongkerd4208f92010-09-20 12:16:13 -0700130int ensure_path_unmounted(const char* path) {
Tao Baobb10e582017-07-22 16:30:34 -0700131 const Volume* v = volume_for_path(path);
132 if (v == nullptr) {
133 LOG(ERROR) << "unknown volume for path [" << path << "]";
134 return -1;
135 }
136 if (strcmp(v->fs_type, "ramdisk") == 0) {
137 // The ramdisk is always mounted; you can't unmount it.
138 return -1;
139 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800140
Tao Baobb10e582017-07-22 16:30:34 -0700141 if (!scan_mounted_volumes()) {
142 LOG(ERROR) << "Failed to scan mounted volumes";
143 return -1;
144 }
Doug Zongkerd4208f92010-09-20 12:16:13 -0700145
Tao Baobb10e582017-07-22 16:30:34 -0700146 MountedVolume* mv = find_mounted_volume_by_mount_point(v->mount_point);
147 if (mv == nullptr) {
148 // Volume is already unmounted.
149 return 0;
150 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800151
Tao Baobb10e582017-07-22 16:30:34 -0700152 return unmount_mounted_volume(mv);
Doug Zongkerd4208f92010-09-20 12:16:13 -0700153}
154
JP Abgrall37aedb32014-06-16 19:07:39 -0700155static int exec_cmd(const char* path, char* const argv[]) {
156 int status;
157 pid_t child;
158 if ((child = vfork()) == 0) {
159 execv(path, argv);
Tao Bao3da88012017-02-03 13:09:23 -0800160 _exit(EXIT_FAILURE);
JP Abgrall37aedb32014-06-16 19:07:39 -0700161 }
162 waitpid(child, &status, 0);
163 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
Tianjie Xu7b0ad9c2016-08-05 18:00:04 -0700164 LOG(ERROR) << path << " failed with status " << WEXITSTATUS(status);
JP Abgrall37aedb32014-06-16 19:07:39 -0700165 }
166 return WEXITSTATUS(status);
167}
168
Jin Qianf3ccad52017-07-24 10:34:35 -0700169static ssize_t get_file_size(int fd, uint64_t reserve_len) {
170 struct stat buf;
171 int ret = fstat(fd, &buf);
172 if (ret) return 0;
173
174 ssize_t computed_size;
175 if (S_ISREG(buf.st_mode)) {
176 computed_size = buf.st_size - reserve_len;
177 } else if (S_ISBLK(buf.st_mode)) {
178 computed_size = get_block_device_size(fd) - reserve_len;
179 } else {
180 computed_size = 0;
181 }
182
183 return computed_size;
184}
185
Paul Lawrenced0db3372015-11-05 13:38:40 -0800186int format_volume(const char* volume, const char* directory) {
Doug Zongkerd4208f92010-09-20 12:16:13 -0700187 Volume* v = volume_for_path(volume);
188 if (v == NULL) {
Tianjie Xu7b0ad9c2016-08-05 18:00:04 -0700189 LOG(ERROR) << "unknown volume \"" << volume << "\"";
Doug Zongkerd4208f92010-09-20 12:16:13 -0700190 return -1;
191 }
Doug Zongkerc18eeb82010-09-21 16:49:26 -0700192 if (strcmp(v->fs_type, "ramdisk") == 0) {
193 // you can't format the ramdisk.
Tianjie Xu7b0ad9c2016-08-05 18:00:04 -0700194 LOG(ERROR) << "can't format_volume \"" << volume << "\"";
Doug Zongkerc18eeb82010-09-21 16:49:26 -0700195 return -1;
196 }
Doug Zongkerd4208f92010-09-20 12:16:13 -0700197 if (strcmp(v->mount_point, volume) != 0) {
Tianjie Xu7b0ad9c2016-08-05 18:00:04 -0700198 LOG(ERROR) << "can't give path \"" << volume << "\" to format_volume";
Doug Zongkerd4208f92010-09-20 12:16:13 -0700199 return -1;
200 }
201
202 if (ensure_path_unmounted(volume) != 0) {
Tianjie Xu7b0ad9c2016-08-05 18:00:04 -0700203 LOG(ERROR) << "format_volume failed to unmount \"" << v->mount_point << "\"";
Doug Zongkerd4208f92010-09-20 12:16:13 -0700204 return -1;
205 }
206
JP Abgrall37aedb32014-06-16 19:07:39 -0700207 if (strcmp(v->fs_type, "ext4") == 0 || strcmp(v->fs_type, "f2fs") == 0) {
Doug Zongkerf39989a2013-12-11 15:40:28 -0800208 // if there's a key_loc that looks like a path, it should be a
209 // block device for storing encryption metadata. wipe it too.
210 if (v->key_loc != NULL && v->key_loc[0] == '/') {
Tianjie Xu7b0ad9c2016-08-05 18:00:04 -0700211 LOG(INFO) << "wiping " << v->key_loc;
Doug Zongkerf39989a2013-12-11 15:40:28 -0800212 int fd = open(v->key_loc, O_WRONLY | O_CREAT, 0644);
213 if (fd < 0) {
Tianjie Xu7b0ad9c2016-08-05 18:00:04 -0700214 LOG(ERROR) << "format_volume: failed to open " << v->key_loc;
Doug Zongkerf39989a2013-12-11 15:40:28 -0800215 return -1;
216 }
217 wipe_block_device(fd, get_file_size(fd));
218 close(fd);
219 }
220
JP Abgrall37aedb32014-06-16 19:07:39 -0700221 ssize_t length = 0;
222 if (v->length != 0) {
223 length = v->length;
224 } else if (v->key_loc != NULL && strcmp(v->key_loc, "footer") == 0) {
Jin Qianf3ccad52017-07-24 10:34:35 -0700225 android::base::unique_fd fd(open(v->blk_device, O_RDONLY));
226 if (fd < 0) {
227 PLOG(ERROR) << "get_file_size: failed to open " << v->blk_device;
228 return -1;
229 }
230 length = get_file_size(fd.get(), CRYPT_FOOTER_OFFSET);
231 if (length <= 0) {
232 LOG(ERROR) << "get_file_size: invalid size " << length << " for " << v->blk_device;
233 return -1;
234 }
JP Abgrall37aedb32014-06-16 19:07:39 -0700235 }
236 int result;
237 if (strcmp(v->fs_type, "ext4") == 0) {
Jin Qianded2dac2017-04-21 14:36:12 -0700238 static constexpr int block_size = 4096;
239 int raid_stride = v->logical_blk_size / block_size;
240 int raid_stripe_width = v->erase_blk_size / block_size;
241
242 // stride should be the max of 8kb and logical block size
243 if (v->logical_blk_size != 0 && v->logical_blk_size < 8192) {
244 raid_stride = 8192 / block_size;
245 }
246
247 const char* mke2fs_argv[] = { "/sbin/mke2fs_static",
248 "-F",
249 "-t",
250 "ext4",
251 "-b",
252 nullptr,
253 nullptr,
254 nullptr,
255 nullptr,
256 nullptr,
257 nullptr };
258
259 int i = 5;
260 std::string block_size_str = std::to_string(block_size);
261 mke2fs_argv[i++] = block_size_str.c_str();
262
263 std::string ext_args;
264 if (v->erase_blk_size != 0 && v->logical_blk_size != 0) {
265 ext_args = android::base::StringPrintf("stride=%d,stripe-width=%d", raid_stride,
266 raid_stripe_width);
267 mke2fs_argv[i++] = "-E";
268 mke2fs_argv[i++] = ext_args.c_str();
269 }
270
271 mke2fs_argv[i++] = v->blk_device;
272
273 std::string size_str = std::to_string(length / block_size);
274 if (length != 0) {
275 mke2fs_argv[i++] = size_str.c_str();
276 }
277
278 result = exec_cmd(mke2fs_argv[0], const_cast<char**>(mke2fs_argv));
279 if (result == 0 && directory != nullptr) {
280 const char* e2fsdroid_argv[] = { "/sbin/e2fsdroid_static",
281 "-e",
Jin Qianded2dac2017-04-21 14:36:12 -0700282 "-f",
283 directory,
284 "-a",
285 volume,
286 v->blk_device,
287 nullptr };
288
289 result = exec_cmd(e2fsdroid_argv[0], const_cast<char**>(e2fsdroid_argv));
Tao Bao338be532017-07-11 16:45:04 -0700290 }
JP Abgrall37aedb32014-06-16 19:07:39 -0700291 } else { /* Has to be f2fs because we checked earlier. */
Jin Qianadeb41a2017-04-28 16:15:13 -0700292 char *num_sectors = nullptr;
293 if (length >= 512 && asprintf(&num_sectors, "%zd", length / 512) <= 0) {
Tianjie Xu7b0ad9c2016-08-05 18:00:04 -0700294 LOG(ERROR) << "format_volume: failed to create " << v->fs_type
295 << " command for " << v->blk_device;
JP Abgrall37aedb32014-06-16 19:07:39 -0700296 return -1;
297 }
298 const char *f2fs_path = "/sbin/mkfs.f2fs";
Jin Qianadeb41a2017-04-28 16:15:13 -0700299 const char* const f2fs_argv[] = {"mkfs.f2fs", "-t", "-d1", v->blk_device, num_sectors, nullptr};
JP Abgrall37aedb32014-06-16 19:07:39 -0700300
301 result = exec_cmd(f2fs_path, (char* const*)f2fs_argv);
302 free(num_sectors);
303 }
304 if (result != 0) {
Tianjie Xu7b0ad9c2016-08-05 18:00:04 -0700305 PLOG(ERROR) << "format_volume: make " << v->fs_type << " failed on " << v->blk_device;
JP Abgrall37aedb32014-06-16 19:07:39 -0700306 return -1;
307 }
Doug Zongkerd4208f92010-09-20 12:16:13 -0700308 return 0;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800309 }
Doug Zongkerd4208f92010-09-20 12:16:13 -0700310
Tianjie Xu7b0ad9c2016-08-05 18:00:04 -0700311 LOG(ERROR) << "format_volume: fs_type \"" << v->fs_type << "\" unsupported";
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800312 return -1;
313}
Doug Zongker239ac6a2013-08-20 16:03:25 -0700314
Paul Lawrenced0db3372015-11-05 13:38:40 -0800315int format_volume(const char* volume) {
Tao Baobb10e582017-07-22 16:30:34 -0700316 return format_volume(volume, nullptr);
Paul Lawrenced0db3372015-11-05 13:38:40 -0800317}
318
Doug Zongker239ac6a2013-08-20 16:03:25 -0700319int setup_install_mounts() {
Tao Bao57130c42017-05-10 12:11:21 -0700320 if (fstab == nullptr) {
321 LOG(ERROR) << "can't set up install mounts: no fstab loaded";
322 return -1;
323 }
324 for (int i = 0; i < fstab->num_entries; ++i) {
325 const Volume* v = fstab->recs + i;
326
327 // We don't want to do anything with "/".
328 if (strcmp(v->mount_point, "/") == 0) {
329 continue;
330 }
331
332 if (strcmp(v->mount_point, "/tmp") == 0 || strcmp(v->mount_point, "/cache") == 0) {
333 if (ensure_path_mounted(v->mount_point) != 0) {
Tao Baobb10e582017-07-22 16:30:34 -0700334 LOG(ERROR) << "Failed to mount " << v->mount_point;
Doug Zongker239ac6a2013-08-20 16:03:25 -0700335 return -1;
Tao Bao57130c42017-05-10 12:11:21 -0700336 }
337 } else {
338 if (ensure_path_unmounted(v->mount_point) != 0) {
Tao Baobb10e582017-07-22 16:30:34 -0700339 LOG(ERROR) << "Failed to unmount " << v->mount_point;
Tao Bao57130c42017-05-10 12:11:21 -0700340 return -1;
341 }
Doug Zongker239ac6a2013-08-20 16:03:25 -0700342 }
Tao Bao57130c42017-05-10 12:11:21 -0700343 }
344 return 0;
Doug Zongker239ac6a2013-08-20 16:03:25 -0700345}