blob: 3788d457b96b5d79408df720a227a1fe203151e1 [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
Koushik Dutta19447c02010-11-10 10:40:44 -080027#include "flashutils/flashutils.h"
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080028#include "minzip/Zip.h"
29#include "roots.h"
30#include "common.h"
31
Koushik Dutta19447c02010-11-10 10:40:44 -080032#include "mounts.h"
Koushik Dutta2f73e582010-04-18 16:00:21 -070033#include "extendedcommands.h"
34
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080035/* Canonical pointers.
36xxx may just want to use enums
37 */
Koushik Dutta19447c02010-11-10 10:40:44 -080038static const char g_default_device[] = "@\0g_default_device";
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080039static const char g_raw[] = "@\0g_raw";
40static const char g_package_file[] = "@\0g_package_file";
41
42static RootInfo g_roots[] = {
Koushik Dutta19447c02010-11-10 10:40:44 -080043 { "BOOT:", g_default_device, NULL, "boot", NULL, g_raw, NULL },
44 { "CACHE:", BOARD_CACHE_DEVICE, NULL, "cache", "/cache", BOARD_CACHE_FILESYSTEM, BOARD_CACHE_FILESYSTEM_OPTIONS },
45 { "DATA:", BOARD_DATA_DEVICE, NULL, "userdata", "/data", BOARD_DATA_FILESYSTEM, BOARD_DATA_FILESYSTEM_OPTIONS },
46#ifdef BOARD_HAS_DATADATA
47 { "DATADATA:", BOARD_DATADATA_DEVICE, NULL, "datadata", "/datadata", BOARD_DATADATA_FILESYSTEM, BOARD_DATADATA_FILESYSTEM_OPTIONS },
Koushik Dutta8b5e1852010-06-14 22:04:22 -070048#endif
Koushik Dutta19447c02010-11-10 10:40:44 -080049 { "MISC:", g_default_device, NULL, "misc", NULL, g_raw, NULL },
Koushik Duttad4060c32010-07-22 20:14:44 -070050 { "PACKAGE:", NULL, NULL, NULL, NULL, g_package_file, NULL },
Koushik Dutta19447c02010-11-10 10:40:44 -080051 { "RECOVERY:", g_default_device, NULL, "recovery", "/", g_raw, NULL },
52 { "SDCARD:", BOARD_SDCARD_DEVICE_PRIMARY, BOARD_SDCARD_DEVICE_SECONDARY, NULL, "/sdcard", "vfat", NULL },
Brint E. Kriebeld3522332010-12-11 20:52:06 -070053#ifdef BOARD_HAS_SDCARD_INTERNAL
54 { "SDINTERNAL:", BOARD_SDCARD_DEVICE_INTERNAL, NULL, NULL, "/emmc", "vfat", NULL },
55#endif
Koushik Dutta19447c02010-11-10 10:40:44 -080056 { "SDEXT:", BOARD_SDEXT_DEVICE, NULL, NULL, "/sd-ext", BOARD_SDEXT_FILESYSTEM, NULL },
57 { "SYSTEM:", BOARD_SYSTEM_DEVICE, NULL, "system", "/system", BOARD_SYSTEM_FILESYSTEM, BOARD_SYSTEM_FILESYSTEM_OPTIONS },
58 { "MBM:", g_default_device, NULL, "mbm", NULL, g_raw, NULL },
Koushik Duttad4060c32010-07-22 20:14:44 -070059 { "TMP:", NULL, NULL, NULL, "/tmp", NULL, NULL },
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080060};
61#define NUM_ROOTS (sizeof(g_roots) / sizeof(g_roots[0]))
62
63// TODO: for SDCARD:, try /dev/block/mmcblk0 if mmcblk0p1 fails
64
Koushik Dutta14239d22010-06-14 15:02:48 -070065const RootInfo *
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080066get_root_info_for_path(const char *root_path)
67{
68 const char *c;
69
70 /* Find the first colon.
71 */
72 c = root_path;
73 while (*c != '\0' && *c != ':') {
74 c++;
75 }
76 if (*c == '\0') {
77 return NULL;
78 }
79 size_t len = c - root_path + 1;
80 size_t i;
81 for (i = 0; i < NUM_ROOTS; i++) {
82 RootInfo *info = &g_roots[i];
83 if (strncmp(info->name, root_path, len) == 0) {
84 return info;
85 }
86 }
87 return NULL;
88}
89
90static const ZipArchive *g_package = NULL;
91static char *g_package_path = NULL;
92
93int
94register_package_root(const ZipArchive *package, const char *package_path)
95{
96 if (package != NULL) {
97 package_path = strdup(package_path);
98 if (package_path == NULL) {
99 return -1;
100 }
101 g_package_path = (char *)package_path;
102 } else {
103 free(g_package_path);
104 g_package_path = NULL;
105 }
106 g_package = package;
107 return 0;
108}
109
110int
111is_package_root_path(const char *root_path)
112{
113 const RootInfo *info = get_root_info_for_path(root_path);
114 return info != NULL && info->filesystem == g_package_file;
115}
116
117const char *
118translate_package_root_path(const char *root_path,
119 char *out_buf, size_t out_buf_len, const ZipArchive **out_package)
120{
121 const RootInfo *info = get_root_info_for_path(root_path);
122 if (info == NULL || info->filesystem != g_package_file) {
123 return NULL;
124 }
125
126 /* Strip the package root off of the path.
127 */
128 size_t root_len = strlen(info->name);
129 root_path += root_len;
130 size_t root_path_len = strlen(root_path);
131
132 if (out_buf_len < root_path_len + 1) {
133 return NULL;
134 }
135 strcpy(out_buf, root_path);
136 *out_package = g_package;
137 return out_buf;
138}
139
140/* Takes a string like "SYSTEM:lib" and turns it into a string
141 * like "/system/lib". The translated path is put in out_buf,
142 * and out_buf is returned if the translation succeeded.
143 */
144const char *
145translate_root_path(const char *root_path, char *out_buf, size_t out_buf_len)
146{
147 if (out_buf_len < 1) {
148 return NULL;
149 }
150
151 const RootInfo *info = get_root_info_for_path(root_path);
152 if (info == NULL || info->mount_point == NULL) {
153 return NULL;
154 }
155
156 /* Find the relative part of the non-root part of the path.
157 */
158 root_path += strlen(info->name); // strip off the "root:"
159 while (*root_path != '\0' && *root_path == '/') {
160 root_path++;
161 }
162
163 size_t mp_len = strlen(info->mount_point);
164 size_t rp_len = strlen(root_path);
165 if (mp_len + 1 + rp_len + 1 > out_buf_len) {
166 return NULL;
167 }
168
169 /* Glue the mount point to the relative part of the path.
170 */
171 memcpy(out_buf, info->mount_point, mp_len);
172 if (out_buf[mp_len - 1] != '/') out_buf[mp_len++] = '/';
173
174 memcpy(out_buf + mp_len, root_path, rp_len);
175 out_buf[mp_len + rp_len] = '\0';
176
177 return out_buf;
178}
179
180static int
181internal_root_mounted(const RootInfo *info)
182{
183 if (info->mount_point == NULL) {
184 return -1;
185 }
186//xxx if TMP: (or similar) just say "yes"
187
188 /* See if this root is already mounted.
189 */
190 int ret = scan_mounted_volumes();
191 if (ret < 0) {
192 return ret;
193 }
194 const MountedVolume *volume;
195 volume = find_mounted_volume_by_mount_point(info->mount_point);
196 if (volume != NULL) {
197 /* It's already mounted.
198 */
199 return 0;
200 }
201 return -1;
202}
203
204int
205is_root_path_mounted(const char *root_path)
206{
207 const RootInfo *info = get_root_info_for_path(root_path);
208 if (info == NULL) {
209 return -1;
210 }
211 return internal_root_mounted(info) >= 0;
212}
213
Koushik Duttad4060c32010-07-22 20:14:44 -0700214static int mount_internal(const char* device, const char* mount_point, const char* filesystem, const char* filesystem_options)
Koushik Dutta1bf4f692010-07-14 18:37:33 -0700215{
Koushik Duttad4060c32010-07-22 20:14:44 -0700216 if (strcmp(filesystem, "auto") != 0 && filesystem_options == NULL) {
Koushik Dutta1bf4f692010-07-14 18:37:33 -0700217 return mount(device, mount_point, filesystem, MS_NOATIME | MS_NODEV | MS_NODIRATIME, "");
218 }
219 else {
220 char mount_cmd[PATH_MAX];
Koushik Duttad4060c32010-07-22 20:14:44 -0700221 const char* options = filesystem_options == NULL ? "noatime,nodiratime,nodev" : filesystem_options;
222 sprintf(mount_cmd, "mount -t %s -o%s %s %s", filesystem, options, device, mount_point);
Koushik Dutta1bf4f692010-07-14 18:37:33 -0700223 return __system(mount_cmd);
224 }
225}
226
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800227int
228ensure_root_path_mounted(const char *root_path)
229{
230 const RootInfo *info = get_root_info_for_path(root_path);
231 if (info == NULL) {
232 return -1;
233 }
234
235 int ret = internal_root_mounted(info);
236 if (ret >= 0) {
237 /* It's already mounted.
238 */
239 return 0;
240 }
241
242 /* It's not mounted.
243 */
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800244 if (info->device == NULL || info->mount_point == NULL ||
245 info->filesystem == NULL ||
246 info->filesystem == g_raw ||
247 info->filesystem == g_package_file) {
248 return -1;
249 }
250
Koushik Dutta19447c02010-11-10 10:40:44 -0800251 if (info->device == g_default_device) {
252 if (info->partition_name == NULL) {
253 return -1;
254 }
255 return mount_partition(info->partition_name, info->mount_point, info->filesystem, 0);
256 }
257
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800258 mkdir(info->mount_point, 0755); // in case it doesn't already exist
Koushik Duttad4060c32010-07-22 20:14:44 -0700259 if (mount_internal(info->device, info->mount_point, info->filesystem, info->filesystem_options)) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800260 if (info->device2 == NULL) {
261 LOGE("Can't mount %s\n(%s)\n", info->device, strerror(errno));
262 return -1;
263 } else if (mount(info->device2, info->mount_point, info->filesystem,
264 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "")) {
265 LOGE("Can't mount %s (or %s)\n(%s)\n",
266 info->device, info->device2, strerror(errno));
267 return -1;
268 }
269 }
270 return 0;
271}
272
273int
274ensure_root_path_unmounted(const char *root_path)
275{
276 const RootInfo *info = get_root_info_for_path(root_path);
277 if (info == NULL) {
278 return -1;
279 }
280 if (info->mount_point == NULL) {
281 /* This root can't be mounted, so by definition it isn't.
282 */
283 return 0;
284 }
285//xxx if TMP: (or similar) just return error
286
287 /* See if this root is already mounted.
288 */
289 int ret = scan_mounted_volumes();
290 if (ret < 0) {
291 return ret;
292 }
293 const MountedVolume *volume;
294 volume = find_mounted_volume_by_mount_point(info->mount_point);
295 if (volume == NULL) {
296 /* It's not mounted.
297 */
298 return 0;
299 }
300
301 return unmount_mounted_volume(volume);
302}
303
Koushik Dutta19447c02010-11-10 10:40:44 -0800304int
305get_root_partition_device(const char *root_path, char *device)
306{
307 const RootInfo *info = get_root_info_for_path(root_path);
Koushik Duttaddc2e392010-11-27 17:53:50 -0800308 if (info == NULL)
Koushik Dutta19447c02010-11-10 10:40:44 -0800309 {
310 return NULL;
311 }
Koushik Duttaddc2e392010-11-27 17:53:50 -0800312 if (info->device == g_default_device)
313 return get_partition_device(info->partition_name, device);
314 return info->device;
Koushik Dutta19447c02010-11-10 10:40:44 -0800315}
316
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800317const MtdPartition *
318get_root_mtd_partition(const char *root_path)
319{
320 const RootInfo *info = get_root_info_for_path(root_path);
Koushik Dutta19447c02010-11-10 10:40:44 -0800321 if (info == NULL || info->device != g_default_device ||
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800322 info->partition_name == NULL)
323 {
Koushik Duttad4060c32010-07-22 20:14:44 -0700324#ifdef BOARD_HAS_MTD_CACHE
325 if (strcmp(root_path, "CACHE:") != 0)
326 return NULL;
327#else
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800328 return NULL;
Koushik Duttad4060c32010-07-22 20:14:44 -0700329#endif
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800330 }
331 mtd_scan_partitions();
332 return mtd_find_partition_by_name(info->partition_name);
333}
Koushik Duttafef77c02010-11-09 20:03:42 -0800334
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800335int
336format_root_device(const char *root)
337{
338 /* Be a little safer here; require that "root" is just
339 * a device with no relative path after it.
340 */
341 const char *c = root;
342 while (*c != '\0' && *c != ':') {
343 c++;
344 }
Koushik Dutta062d6b02010-07-03 13:54:21 -0700345 /*
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800346 if (c[0] != ':' || c[1] != '\0') {
347 LOGW("format_root_device: bad root name \"%s\"\n", root);
348 return -1;
349 }
Koushik Dutta062d6b02010-07-03 13:54:21 -0700350 */
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800351
352 const RootInfo *info = get_root_info_for_path(root);
353 if (info == NULL || info->device == NULL) {
354 LOGW("format_root_device: can't resolve \"%s\"\n", root);
355 return -1;
356 }
Koushik Dutta19447c02010-11-10 10:40:44 -0800357
358 if (info->mount_point != NULL && info->device == g_default_device) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800359 /* Don't try to format a mounted device.
360 */
361 int ret = ensure_root_path_unmounted(root);
362 if (ret < 0) {
363 LOGW("format_root_device: can't unmount \"%s\"\n", root);
364 return ret;
365 }
366 }
367
368 /* Format the device.
369 */
Koushik Dutta19447c02010-11-10 10:40:44 -0800370 if (info->device == g_default_device) {
371 int ret = 0;
372 if (info->filesystem == g_raw)
373 ret = erase_raw_partition(info->partition_name);
374 else
375 ret = erase_partition(info->partition_name, info->filesystem);
376
377 if (ret != 0)
378 LOGE("Error erasing device %s\n", info->device);
379 return ret;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800380 }
Shashank Mittal815ca5d2010-07-27 11:09:19 -0700381
Koushik Dutta19447c02010-11-10 10:40:44 -0800382 return format_unknown_device(root);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800383}