blob: 39179e9a849794b04cd3835af8916e11ceae62c1 [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 },
53 { "SDEXT:", BOARD_SDEXT_DEVICE, NULL, NULL, "/sd-ext", BOARD_SDEXT_FILESYSTEM, NULL },
54 { "SYSTEM:", BOARD_SYSTEM_DEVICE, NULL, "system", "/system", BOARD_SYSTEM_FILESYSTEM, BOARD_SYSTEM_FILESYSTEM_OPTIONS },
55 { "MBM:", g_default_device, NULL, "mbm", NULL, g_raw, NULL },
Koushik Duttad4060c32010-07-22 20:14:44 -070056 { "TMP:", NULL, NULL, NULL, "/tmp", NULL, NULL },
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080057};
58#define NUM_ROOTS (sizeof(g_roots) / sizeof(g_roots[0]))
59
60// TODO: for SDCARD:, try /dev/block/mmcblk0 if mmcblk0p1 fails
61
Koushik Dutta14239d22010-06-14 15:02:48 -070062const RootInfo *
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080063get_root_info_for_path(const char *root_path)
64{
65 const char *c;
66
67 /* Find the first colon.
68 */
69 c = root_path;
70 while (*c != '\0' && *c != ':') {
71 c++;
72 }
73 if (*c == '\0') {
74 return NULL;
75 }
76 size_t len = c - root_path + 1;
77 size_t i;
78 for (i = 0; i < NUM_ROOTS; i++) {
79 RootInfo *info = &g_roots[i];
80 if (strncmp(info->name, root_path, len) == 0) {
81 return info;
82 }
83 }
84 return NULL;
85}
86
87static const ZipArchive *g_package = NULL;
88static char *g_package_path = NULL;
89
90int
91register_package_root(const ZipArchive *package, const char *package_path)
92{
93 if (package != NULL) {
94 package_path = strdup(package_path);
95 if (package_path == NULL) {
96 return -1;
97 }
98 g_package_path = (char *)package_path;
99 } else {
100 free(g_package_path);
101 g_package_path = NULL;
102 }
103 g_package = package;
104 return 0;
105}
106
107int
108is_package_root_path(const char *root_path)
109{
110 const RootInfo *info = get_root_info_for_path(root_path);
111 return info != NULL && info->filesystem == g_package_file;
112}
113
114const char *
115translate_package_root_path(const char *root_path,
116 char *out_buf, size_t out_buf_len, const ZipArchive **out_package)
117{
118 const RootInfo *info = get_root_info_for_path(root_path);
119 if (info == NULL || info->filesystem != g_package_file) {
120 return NULL;
121 }
122
123 /* Strip the package root off of the path.
124 */
125 size_t root_len = strlen(info->name);
126 root_path += root_len;
127 size_t root_path_len = strlen(root_path);
128
129 if (out_buf_len < root_path_len + 1) {
130 return NULL;
131 }
132 strcpy(out_buf, root_path);
133 *out_package = g_package;
134 return out_buf;
135}
136
137/* Takes a string like "SYSTEM:lib" and turns it into a string
138 * like "/system/lib". The translated path is put in out_buf,
139 * and out_buf is returned if the translation succeeded.
140 */
141const char *
142translate_root_path(const char *root_path, char *out_buf, size_t out_buf_len)
143{
144 if (out_buf_len < 1) {
145 return NULL;
146 }
147
148 const RootInfo *info = get_root_info_for_path(root_path);
149 if (info == NULL || info->mount_point == NULL) {
150 return NULL;
151 }
152
153 /* Find the relative part of the non-root part of the path.
154 */
155 root_path += strlen(info->name); // strip off the "root:"
156 while (*root_path != '\0' && *root_path == '/') {
157 root_path++;
158 }
159
160 size_t mp_len = strlen(info->mount_point);
161 size_t rp_len = strlen(root_path);
162 if (mp_len + 1 + rp_len + 1 > out_buf_len) {
163 return NULL;
164 }
165
166 /* Glue the mount point to the relative part of the path.
167 */
168 memcpy(out_buf, info->mount_point, mp_len);
169 if (out_buf[mp_len - 1] != '/') out_buf[mp_len++] = '/';
170
171 memcpy(out_buf + mp_len, root_path, rp_len);
172 out_buf[mp_len + rp_len] = '\0';
173
174 return out_buf;
175}
176
177static int
178internal_root_mounted(const RootInfo *info)
179{
180 if (info->mount_point == NULL) {
181 return -1;
182 }
183//xxx if TMP: (or similar) just say "yes"
184
185 /* See if this root is already mounted.
186 */
187 int ret = scan_mounted_volumes();
188 if (ret < 0) {
189 return ret;
190 }
191 const MountedVolume *volume;
192 volume = find_mounted_volume_by_mount_point(info->mount_point);
193 if (volume != NULL) {
194 /* It's already mounted.
195 */
196 return 0;
197 }
198 return -1;
199}
200
201int
202is_root_path_mounted(const char *root_path)
203{
204 const RootInfo *info = get_root_info_for_path(root_path);
205 if (info == NULL) {
206 return -1;
207 }
208 return internal_root_mounted(info) >= 0;
209}
210
Koushik Duttad4060c32010-07-22 20:14:44 -0700211static int mount_internal(const char* device, const char* mount_point, const char* filesystem, const char* filesystem_options)
Koushik Dutta1bf4f692010-07-14 18:37:33 -0700212{
Koushik Duttad4060c32010-07-22 20:14:44 -0700213 if (strcmp(filesystem, "auto") != 0 && filesystem_options == NULL) {
Koushik Dutta1bf4f692010-07-14 18:37:33 -0700214 return mount(device, mount_point, filesystem, MS_NOATIME | MS_NODEV | MS_NODIRATIME, "");
215 }
216 else {
217 char mount_cmd[PATH_MAX];
Koushik Duttad4060c32010-07-22 20:14:44 -0700218 const char* options = filesystem_options == NULL ? "noatime,nodiratime,nodev" : filesystem_options;
219 sprintf(mount_cmd, "mount -t %s -o%s %s %s", filesystem, options, device, mount_point);
Koushik Dutta1bf4f692010-07-14 18:37:33 -0700220 return __system(mount_cmd);
221 }
222}
223
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800224int
225ensure_root_path_mounted(const char *root_path)
226{
227 const RootInfo *info = get_root_info_for_path(root_path);
228 if (info == NULL) {
229 return -1;
230 }
231
232 int ret = internal_root_mounted(info);
233 if (ret >= 0) {
234 /* It's already mounted.
235 */
236 return 0;
237 }
238
239 /* It's not mounted.
240 */
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800241 if (info->device == NULL || info->mount_point == NULL ||
242 info->filesystem == NULL ||
243 info->filesystem == g_raw ||
244 info->filesystem == g_package_file) {
245 return -1;
246 }
247
Koushik Dutta19447c02010-11-10 10:40:44 -0800248 if (info->device == g_default_device) {
249 if (info->partition_name == NULL) {
250 return -1;
251 }
252 return mount_partition(info->partition_name, info->mount_point, info->filesystem, 0);
253 }
254
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800255 mkdir(info->mount_point, 0755); // in case it doesn't already exist
Koushik Duttad4060c32010-07-22 20:14:44 -0700256 if (mount_internal(info->device, info->mount_point, info->filesystem, info->filesystem_options)) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800257 if (info->device2 == NULL) {
258 LOGE("Can't mount %s\n(%s)\n", info->device, strerror(errno));
259 return -1;
260 } else if (mount(info->device2, info->mount_point, info->filesystem,
261 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "")) {
262 LOGE("Can't mount %s (or %s)\n(%s)\n",
263 info->device, info->device2, strerror(errno));
264 return -1;
265 }
266 }
267 return 0;
268}
269
270int
271ensure_root_path_unmounted(const char *root_path)
272{
273 const RootInfo *info = get_root_info_for_path(root_path);
274 if (info == NULL) {
275 return -1;
276 }
277 if (info->mount_point == NULL) {
278 /* This root can't be mounted, so by definition it isn't.
279 */
280 return 0;
281 }
282//xxx if TMP: (or similar) just return error
283
284 /* See if this root is already mounted.
285 */
286 int ret = scan_mounted_volumes();
287 if (ret < 0) {
288 return ret;
289 }
290 const MountedVolume *volume;
291 volume = find_mounted_volume_by_mount_point(info->mount_point);
292 if (volume == NULL) {
293 /* It's not mounted.
294 */
295 return 0;
296 }
297
298 return unmount_mounted_volume(volume);
299}
300
Koushik Dutta19447c02010-11-10 10:40:44 -0800301int
302get_root_partition_device(const char *root_path, char *device)
303{
304 const RootInfo *info = get_root_info_for_path(root_path);
305 if (info == NULL || info->device != g_default_device ||
306 info->partition_name == NULL)
307 {
308 return NULL;
309 }
310 return get_partition_device(info->partition_name, device);
311}
312
313#ifndef BOARD_HAS_NO_MISC_PARTITION
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800314const MtdPartition *
315get_root_mtd_partition(const char *root_path)
316{
317 const RootInfo *info = get_root_info_for_path(root_path);
Koushik Dutta19447c02010-11-10 10:40:44 -0800318 if (info == NULL || info->device != g_default_device ||
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800319 info->partition_name == NULL)
320 {
Koushik Duttad4060c32010-07-22 20:14:44 -0700321#ifdef BOARD_HAS_MTD_CACHE
322 if (strcmp(root_path, "CACHE:") != 0)
323 return NULL;
324#else
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800325 return NULL;
Koushik Duttad4060c32010-07-22 20:14:44 -0700326#endif
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800327 }
328 mtd_scan_partitions();
329 return mtd_find_partition_by_name(info->partition_name);
330}
Koushik Dutta19447c02010-11-10 10:40:44 -0800331#endif
Koushik Duttafef77c02010-11-09 20:03:42 -0800332
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800333int
334format_root_device(const char *root)
335{
336 /* Be a little safer here; require that "root" is just
337 * a device with no relative path after it.
338 */
339 const char *c = root;
340 while (*c != '\0' && *c != ':') {
341 c++;
342 }
Koushik Dutta062d6b02010-07-03 13:54:21 -0700343 /*
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800344 if (c[0] != ':' || c[1] != '\0') {
345 LOGW("format_root_device: bad root name \"%s\"\n", root);
346 return -1;
347 }
Koushik Dutta062d6b02010-07-03 13:54:21 -0700348 */
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800349
350 const RootInfo *info = get_root_info_for_path(root);
351 if (info == NULL || info->device == NULL) {
352 LOGW("format_root_device: can't resolve \"%s\"\n", root);
353 return -1;
354 }
Koushik Dutta19447c02010-11-10 10:40:44 -0800355
356 if (info->mount_point != NULL && info->device == g_default_device) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800357 /* Don't try to format a mounted device.
358 */
359 int ret = ensure_root_path_unmounted(root);
360 if (ret < 0) {
361 LOGW("format_root_device: can't unmount \"%s\"\n", root);
362 return ret;
363 }
364 }
365
366 /* Format the device.
367 */
Koushik Dutta19447c02010-11-10 10:40:44 -0800368 if (info->device == g_default_device) {
369 int ret = 0;
370 if (info->filesystem == g_raw)
371 ret = erase_raw_partition(info->partition_name);
372 else
373 ret = erase_partition(info->partition_name, info->filesystem);
374
375 if (ret != 0)
376 LOGE("Error erasing device %s\n", info->device);
377 return ret;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800378 }
Shashank Mittal815ca5d2010-07-27 11:09:19 -0700379
Koushik Dutta19447c02010-11-10 10:40:44 -0800380 return format_unknown_device(root);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800381}