blob: 92b89a41ea91f2cc607d705112b259a7074650b4 [file] [log] [blame]
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
Shashank Mittal815ca5d2010-07-27 11:09:19 -07003 * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08004 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include <errno.h>
19#include <stdlib.h>
20#include <sys/mount.h>
21#include <sys/stat.h>
22#include <sys/types.h>
23#include <unistd.h>
24
Koushik Dutta1bf4f692010-07-14 18:37:33 -070025#include <limits.h>
26
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080027#include "mtdutils/mtdutils.h"
28#include "mtdutils/mounts.h"
Shashank Mittal815ca5d2010-07-27 11:09:19 -070029#include "mmcutils/mmcutils.h"
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080030#include "minzip/Zip.h"
31#include "roots.h"
32#include "common.h"
33
Koushik Dutta2f73e582010-04-18 16:00:21 -070034#include "extendedcommands.h"
35
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080036/* Canonical pointers.
37xxx may just want to use enums
38 */
39static const char g_mtd_device[] = "@\0g_mtd_device";
Shashank Mittal815ca5d2010-07-27 11:09:19 -070040static const char g_mmc_device[] = "@\0g_mmc_device";
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080041static const char g_raw[] = "@\0g_raw";
42static const char g_package_file[] = "@\0g_package_file";
43
44static RootInfo g_roots[] = {
Koushik Duttafef77c02010-11-09 20:03:42 -080045 { "BOOT:", DEFAULT_DEVICE, NULL, "boot", NULL, g_raw, NULL },
Koushik Duttad4060c32010-07-22 20:14:44 -070046 { "CACHE:", CACHE_DEVICE, NULL, "cache", "/cache", CACHE_FILESYSTEM, CACHE_FILESYSTEM_OPTIONS },
47 { "DATA:", DATA_DEVICE, NULL, "userdata", "/data", DATA_FILESYSTEM, DATA_FILESYSTEM_OPTIONS },
Koushik Dutta8b5e1852010-06-14 22:04:22 -070048#ifdef HAS_DATADATA
Koushik Duttad4060c32010-07-22 20:14:44 -070049 { "DATADATA:", DATADATA_DEVICE, NULL, "datadata", "/datadata", DATADATA_FILESYSTEM, DATADATA_FILESYSTEM_OPTIONS },
Koushik Dutta8b5e1852010-06-14 22:04:22 -070050#endif
Koushik Duttafef77c02010-11-09 20:03:42 -080051 { "MISC:", DEFAULT_DEVICE, NULL, "misc", NULL, g_raw, NULL },
Koushik Duttad4060c32010-07-22 20:14:44 -070052 { "PACKAGE:", NULL, NULL, NULL, NULL, g_package_file, NULL },
Koushik Duttafef77c02010-11-09 20:03:42 -080053 { "RECOVERY:", DEFAULT_DEVICE, NULL, "recovery", "/", g_raw, NULL },
Koushik Duttad4060c32010-07-22 20:14:44 -070054 { "SDCARD:", SDCARD_DEVICE_PRIMARY, SDCARD_DEVICE_SECONDARY, NULL, "/sdcard", "vfat", NULL },
55 { "SDEXT:", SDEXT_DEVICE, NULL, NULL, "/sd-ext", SDEXT_FILESYSTEM, NULL },
56 { "SYSTEM:", SYSTEM_DEVICE, NULL, "system", "/system", SYSTEM_FILESYSTEM, SYSTEM_FILESYSTEM_OPTIONS },
Koushik Duttafef77c02010-11-09 20:03:42 -080057 { "MBM:", DEFAULT_DEVICE, NULL, "mbm", NULL, g_raw, NULL },
Koushik Duttad4060c32010-07-22 20:14:44 -070058 { "TMP:", NULL, NULL, NULL, "/tmp", NULL, NULL },
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080059};
60#define NUM_ROOTS (sizeof(g_roots) / sizeof(g_roots[0]))
61
62// TODO: for SDCARD:, try /dev/block/mmcblk0 if mmcblk0p1 fails
63
Koushik Dutta14239d22010-06-14 15:02:48 -070064const RootInfo *
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080065get_root_info_for_path(const char *root_path)
66{
67 const char *c;
68
69 /* Find the first colon.
70 */
71 c = root_path;
72 while (*c != '\0' && *c != ':') {
73 c++;
74 }
75 if (*c == '\0') {
76 return NULL;
77 }
78 size_t len = c - root_path + 1;
79 size_t i;
80 for (i = 0; i < NUM_ROOTS; i++) {
81 RootInfo *info = &g_roots[i];
82 if (strncmp(info->name, root_path, len) == 0) {
83 return info;
84 }
85 }
86 return NULL;
87}
88
89static const ZipArchive *g_package = NULL;
90static char *g_package_path = NULL;
91
92int
93register_package_root(const ZipArchive *package, const char *package_path)
94{
95 if (package != NULL) {
96 package_path = strdup(package_path);
97 if (package_path == NULL) {
98 return -1;
99 }
100 g_package_path = (char *)package_path;
101 } else {
102 free(g_package_path);
103 g_package_path = NULL;
104 }
105 g_package = package;
106 return 0;
107}
108
109int
110is_package_root_path(const char *root_path)
111{
112 const RootInfo *info = get_root_info_for_path(root_path);
113 return info != NULL && info->filesystem == g_package_file;
114}
115
116const char *
117translate_package_root_path(const char *root_path,
118 char *out_buf, size_t out_buf_len, const ZipArchive **out_package)
119{
120 const RootInfo *info = get_root_info_for_path(root_path);
121 if (info == NULL || info->filesystem != g_package_file) {
122 return NULL;
123 }
124
125 /* Strip the package root off of the path.
126 */
127 size_t root_len = strlen(info->name);
128 root_path += root_len;
129 size_t root_path_len = strlen(root_path);
130
131 if (out_buf_len < root_path_len + 1) {
132 return NULL;
133 }
134 strcpy(out_buf, root_path);
135 *out_package = g_package;
136 return out_buf;
137}
138
139/* Takes a string like "SYSTEM:lib" and turns it into a string
140 * like "/system/lib". The translated path is put in out_buf,
141 * and out_buf is returned if the translation succeeded.
142 */
143const char *
144translate_root_path(const char *root_path, char *out_buf, size_t out_buf_len)
145{
146 if (out_buf_len < 1) {
147 return NULL;
148 }
149
150 const RootInfo *info = get_root_info_for_path(root_path);
151 if (info == NULL || info->mount_point == NULL) {
152 return NULL;
153 }
154
155 /* Find the relative part of the non-root part of the path.
156 */
157 root_path += strlen(info->name); // strip off the "root:"
158 while (*root_path != '\0' && *root_path == '/') {
159 root_path++;
160 }
161
162 size_t mp_len = strlen(info->mount_point);
163 size_t rp_len = strlen(root_path);
164 if (mp_len + 1 + rp_len + 1 > out_buf_len) {
165 return NULL;
166 }
167
168 /* Glue the mount point to the relative part of the path.
169 */
170 memcpy(out_buf, info->mount_point, mp_len);
171 if (out_buf[mp_len - 1] != '/') out_buf[mp_len++] = '/';
172
173 memcpy(out_buf + mp_len, root_path, rp_len);
174 out_buf[mp_len + rp_len] = '\0';
175
176 return out_buf;
177}
178
179static int
180internal_root_mounted(const RootInfo *info)
181{
182 if (info->mount_point == NULL) {
183 return -1;
184 }
185//xxx if TMP: (or similar) just say "yes"
186
187 /* See if this root is already mounted.
188 */
189 int ret = scan_mounted_volumes();
190 if (ret < 0) {
191 return ret;
192 }
193 const MountedVolume *volume;
194 volume = find_mounted_volume_by_mount_point(info->mount_point);
195 if (volume != NULL) {
196 /* It's already mounted.
197 */
198 return 0;
199 }
200 return -1;
201}
202
203int
204is_root_path_mounted(const char *root_path)
205{
206 const RootInfo *info = get_root_info_for_path(root_path);
207 if (info == NULL) {
208 return -1;
209 }
210 return internal_root_mounted(info) >= 0;
211}
212
Koushik Duttad4060c32010-07-22 20:14:44 -0700213static int mount_internal(const char* device, const char* mount_point, const char* filesystem, const char* filesystem_options)
Koushik Dutta1bf4f692010-07-14 18:37:33 -0700214{
Koushik Duttad4060c32010-07-22 20:14:44 -0700215 if (strcmp(filesystem, "auto") != 0 && filesystem_options == NULL) {
Koushik Dutta1bf4f692010-07-14 18:37:33 -0700216 return mount(device, mount_point, filesystem, MS_NOATIME | MS_NODEV | MS_NODIRATIME, "");
217 }
218 else {
219 char mount_cmd[PATH_MAX];
Koushik Duttad4060c32010-07-22 20:14:44 -0700220 const char* options = filesystem_options == NULL ? "noatime,nodiratime,nodev" : filesystem_options;
221 sprintf(mount_cmd, "mount -t %s -o%s %s %s", filesystem, options, device, mount_point);
Koushik Dutta1bf4f692010-07-14 18:37:33 -0700222 return __system(mount_cmd);
223 }
224}
225
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800226int
227ensure_root_path_mounted(const char *root_path)
228{
229 const RootInfo *info = get_root_info_for_path(root_path);
230 if (info == NULL) {
231 return -1;
232 }
233
234 int ret = internal_root_mounted(info);
235 if (ret >= 0) {
236 /* It's already mounted.
237 */
238 return 0;
239 }
240
241 /* It's not mounted.
242 */
243 if (info->device == g_mtd_device) {
244 if (info->partition_name == NULL) {
245 return -1;
246 }
247//TODO: make the mtd stuff scan once when it needs to
248 mtd_scan_partitions();
249 const MtdPartition *partition;
250 partition = mtd_find_partition_by_name(info->partition_name);
251 if (partition == NULL) {
252 return -1;
253 }
254 return mtd_mount_partition(partition, info->mount_point,
255 info->filesystem, 0);
256 }
257
Koushik Duttafef77c02010-11-09 20:03:42 -0800258 if (info->device == g_mmc_device) {
259 if (info->partition_name == NULL) {
260 return -1;
261 }
262//TODO: make the mtd stuff scan once when it needs to
263 mmc_scan_partitions();
264 const MmcPartition *partition;
265 partition = mmc_find_partition_by_name(info->partition_name);
266 if (partition == NULL) {
267 return -1;
268 }
269 return mmc_mount_partition(partition, info->mount_point, 0);
270 }
271
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800272 if (info->device == NULL || info->mount_point == NULL ||
273 info->filesystem == NULL ||
274 info->filesystem == g_raw ||
275 info->filesystem == g_package_file) {
276 return -1;
277 }
278
279 mkdir(info->mount_point, 0755); // in case it doesn't already exist
Koushik Duttad4060c32010-07-22 20:14:44 -0700280 if (mount_internal(info->device, info->mount_point, info->filesystem, info->filesystem_options)) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800281 if (info->device2 == NULL) {
282 LOGE("Can't mount %s\n(%s)\n", info->device, strerror(errno));
283 return -1;
284 } else if (mount(info->device2, info->mount_point, info->filesystem,
285 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "")) {
286 LOGE("Can't mount %s (or %s)\n(%s)\n",
287 info->device, info->device2, strerror(errno));
288 return -1;
289 }
290 }
291 return 0;
292}
293
294int
295ensure_root_path_unmounted(const char *root_path)
296{
297 const RootInfo *info = get_root_info_for_path(root_path);
298 if (info == NULL) {
299 return -1;
300 }
301 if (info->mount_point == NULL) {
302 /* This root can't be mounted, so by definition it isn't.
303 */
304 return 0;
305 }
306//xxx if TMP: (or similar) just return error
307
308 /* See if this root is already mounted.
309 */
310 int ret = scan_mounted_volumes();
311 if (ret < 0) {
312 return ret;
313 }
314 const MountedVolume *volume;
315 volume = find_mounted_volume_by_mount_point(info->mount_point);
316 if (volume == NULL) {
317 /* It's not mounted.
318 */
319 return 0;
320 }
321
322 return unmount_mounted_volume(volume);
323}
324
325const MtdPartition *
326get_root_mtd_partition(const char *root_path)
327{
328 const RootInfo *info = get_root_info_for_path(root_path);
329 if (info == NULL || info->device != g_mtd_device ||
330 info->partition_name == NULL)
331 {
Koushik Duttad4060c32010-07-22 20:14:44 -0700332#ifdef BOARD_HAS_MTD_CACHE
333 if (strcmp(root_path, "CACHE:") != 0)
334 return NULL;
335#else
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800336 return NULL;
Koushik Duttad4060c32010-07-22 20:14:44 -0700337#endif
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800338 }
339 mtd_scan_partitions();
340 return mtd_find_partition_by_name(info->partition_name);
341}
342
Koushik Duttafef77c02010-11-09 20:03:42 -0800343const MmcPartition *
344get_root_mmc_partition(const char *root_path)
345{
346 const RootInfo *info = get_root_info_for_path(root_path);
347 if (info == NULL || info->device != g_mmc_device ||
348 info->partition_name == NULL)
349 {
350 return NULL;
351 }
352 mmc_scan_partitions();
353 return mmc_find_partition_by_name(info->partition_name);
354}
355
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800356int
357format_root_device(const char *root)
358{
359 /* Be a little safer here; require that "root" is just
360 * a device with no relative path after it.
361 */
362 const char *c = root;
363 while (*c != '\0' && *c != ':') {
364 c++;
365 }
Koushik Dutta062d6b02010-07-03 13:54:21 -0700366 /*
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800367 if (c[0] != ':' || c[1] != '\0') {
368 LOGW("format_root_device: bad root name \"%s\"\n", root);
369 return -1;
370 }
Koushik Dutta062d6b02010-07-03 13:54:21 -0700371 */
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800372
373 const RootInfo *info = get_root_info_for_path(root);
374 if (info == NULL || info->device == NULL) {
375 LOGW("format_root_device: can't resolve \"%s\"\n", root);
376 return -1;
377 }
Koushik Duttafef77c02010-11-09 20:03:42 -0800378 if (info->mount_point != NULL && (info->device == g_mtd_device || info->device == g_mmc_device)) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800379 /* Don't try to format a mounted device.
380 */
381 int ret = ensure_root_path_unmounted(root);
382 if (ret < 0) {
383 LOGW("format_root_device: can't unmount \"%s\"\n", root);
384 return ret;
385 }
386 }
387
388 /* Format the device.
389 */
390 if (info->device == g_mtd_device) {
391 mtd_scan_partitions();
392 const MtdPartition *partition;
393 partition = mtd_find_partition_by_name(info->partition_name);
394 if (partition == NULL) {
395 LOGW("format_root_device: can't find mtd partition \"%s\"\n",
396 info->partition_name);
397 return -1;
398 }
399 if (info->filesystem == g_raw || !strcmp(info->filesystem, "yaffs2")) {
400 MtdWriteContext *write = mtd_write_partition(partition);
401 if (write == NULL) {
402 LOGW("format_root_device: can't open \"%s\"\n", root);
403 return -1;
404 } else if (mtd_erase_blocks(write, -1) == (off_t) -1) {
405 LOGW("format_root_device: can't erase \"%s\"\n", root);
406 mtd_write_close(write);
407 return -1;
408 } else if (mtd_write_close(write)) {
409 LOGW("format_root_device: can't close \"%s\"\n", root);
410 return -1;
411 } else {
412 return 0;
413 }
414 }
415 }
Shashank Mittal815ca5d2010-07-27 11:09:19 -0700416
417 //Handle MMC device types
418 if(info->device == g_mmc_device) {
419 mmc_scan_partitions();
420 const MmcPartition *partition;
421 partition = mmc_find_partition_by_name(info->partition_name);
422 if (partition == NULL) {
423 LOGE("format_root_device: can't find mmc partition \"%s\"\n",
424 info->partition_name);
425 return -1;
426 }
427 if (!strcmp(info->filesystem, "ext3")) {
Koushik Duttafef77c02010-11-09 20:03:42 -0800428 if(0 == mmc_format_ext3(partition))
429 return 0;
430 LOGE("\n\"%s\" wipe failed!\n", info->partition_name);
431 return -1;
Shashank Mittal815ca5d2010-07-27 11:09:19 -0700432 }
Koushik Duttafef77c02010-11-09 20:03:42 -0800433 LOGW("\n\"%s\" wipe skipped!\n", info->partition_name);
434 return 0;
Shashank Mittal815ca5d2010-07-27 11:09:19 -0700435 }
436
Koushik Dutta2f73e582010-04-18 16:00:21 -0700437 return format_non_mtd_device(root);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800438}