blob: b2df224cfe4678d9968a1d26b70e9d78d98099fb [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
17#include <errno.h>
18#include <stdlib.h>
19#include <sys/mount.h>
20#include <sys/stat.h>
21#include <sys/types.h>
22#include <unistd.h>
23
24#include "mtdutils/mtdutils.h"
25#include "mtdutils/mounts.h"
26#include "minzip/Zip.h"
27#include "roots.h"
28#include "common.h"
29
Koushik Dutta2f73e582010-04-18 16:00:21 -070030#include "extendedcommands.h"
31
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080032/* Canonical pointers.
33xxx may just want to use enums
34 */
35static const char g_mtd_device[] = "@\0g_mtd_device";
36static const char g_raw[] = "@\0g_raw";
37static const char g_package_file[] = "@\0g_package_file";
38
Koushik Dutta14239d22010-06-14 15:02:48 -070039#ifndef SDCARD_DEVICE_PRIMARY
40#define SDCARD_DEVICE_PRIMARY "/dev/block/mmcblk0p1"
Koushik Duttaf8b21c22010-06-14 12:49:47 -070041#endif
42
Koushik Dutta14239d22010-06-14 15:02:48 -070043#ifndef SDCARD_DEVICE_SECONDARY
44#define SDCARD_DEVICE_SECONDARY "/dev/block/mmcblk0p2"
Koushik Duttaf8b21c22010-06-14 12:49:47 -070045#endif
46
Koushik Dutta14239d22010-06-14 15:02:48 -070047#ifndef SDEXT_DEVICE
48#define SDEXT_DEVICE "/dev/block/mmcblk0p2"
Koushik Duttaf8b21c22010-06-14 12:49:47 -070049#endif
50
Koushik Dutta14239d22010-06-14 15:02:48 -070051#ifndef SDEXT_FILESYSTEM
52#define SDEXT_FILESYSTEM "ext4"
53#endif
54
55#ifndef DATA_DEVICE
56#define DATA_DEVICE g_mtd_device
57#endif
58
59#ifndef DATA_FILESYSTEM
60#define DATA_FILESYSTEM "yaffs2"
61#endif
62
Koushik Dutta8b5e1852010-06-14 22:04:22 -070063#ifndef DATADATA_DEVICE
64#define DATADATA_DEVICE g_mtd_device
65#endif
66
67#ifndef DATADATA_FILESYSTEM
68#define DATADATA_FILESYSTEM "yaffs2"
69#endif
70
Koushik Dutta14239d22010-06-14 15:02:48 -070071#ifndef CACHE_DEVICE
72#define CACHE_DEVICE g_mtd_device
73#endif
74
75#ifndef CACHE_FILESYSTEM
76#define CACHE_FILESYSTEM "yaffs2"
Koushik Duttaf8b21c22010-06-14 12:49:47 -070077#endif
78
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080079static RootInfo g_roots[] = {
80 { "BOOT:", g_mtd_device, NULL, "boot", NULL, g_raw },
Koushik Dutta14239d22010-06-14 15:02:48 -070081 { "CACHE:", CACHE_DEVICE, NULL, "cache", "/cache", CACHE_FILESYSTEM },
82 { "DATA:", DATA_DEVICE, NULL, "userdata", "/data", DATA_FILESYSTEM },
Koushik Dutta8b5e1852010-06-14 22:04:22 -070083#ifdef HAS_DATADATA
84 { "DATADATA:", DATADATA_DEVICE, NULL, "datadata", "/datadata", DATADATA_FILESYSTEM },
85#endif
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080086 { "MISC:", g_mtd_device, NULL, "misc", NULL, g_raw },
87 { "PACKAGE:", NULL, NULL, NULL, NULL, g_package_file },
88 { "RECOVERY:", g_mtd_device, NULL, "recovery", "/", g_raw },
Koushik Dutta14239d22010-06-14 15:02:48 -070089 { "SDCARD:", SDCARD_DEVICE_PRIMARY, SDCARD_DEVICE_SECONDARY, NULL, "/sdcard", "vfat" },
90 { "SDEXT:", SDEXT_DEVICE, NULL, NULL, "/sd-ext", SDEXT_FILESYSTEM },
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080091 { "SYSTEM:", g_mtd_device, NULL, "system", "/system", "yaffs2" },
Doug Zongkerb128f542009-06-18 15:07:14 -070092 { "MBM:", g_mtd_device, NULL, "mbm", NULL, g_raw },
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080093 { "TMP:", NULL, NULL, NULL, "/tmp", NULL },
94};
95#define NUM_ROOTS (sizeof(g_roots) / sizeof(g_roots[0]))
96
97// TODO: for SDCARD:, try /dev/block/mmcblk0 if mmcblk0p1 fails
98
Koushik Dutta14239d22010-06-14 15:02:48 -070099const RootInfo *
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800100get_root_info_for_path(const char *root_path)
101{
102 const char *c;
103
104 /* Find the first colon.
105 */
106 c = root_path;
107 while (*c != '\0' && *c != ':') {
108 c++;
109 }
110 if (*c == '\0') {
111 return NULL;
112 }
113 size_t len = c - root_path + 1;
114 size_t i;
115 for (i = 0; i < NUM_ROOTS; i++) {
116 RootInfo *info = &g_roots[i];
117 if (strncmp(info->name, root_path, len) == 0) {
118 return info;
119 }
120 }
121 return NULL;
122}
123
124static const ZipArchive *g_package = NULL;
125static char *g_package_path = NULL;
126
127int
128register_package_root(const ZipArchive *package, const char *package_path)
129{
130 if (package != NULL) {
131 package_path = strdup(package_path);
132 if (package_path == NULL) {
133 return -1;
134 }
135 g_package_path = (char *)package_path;
136 } else {
137 free(g_package_path);
138 g_package_path = NULL;
139 }
140 g_package = package;
141 return 0;
142}
143
144int
145is_package_root_path(const char *root_path)
146{
147 const RootInfo *info = get_root_info_for_path(root_path);
148 return info != NULL && info->filesystem == g_package_file;
149}
150
151const char *
152translate_package_root_path(const char *root_path,
153 char *out_buf, size_t out_buf_len, const ZipArchive **out_package)
154{
155 const RootInfo *info = get_root_info_for_path(root_path);
156 if (info == NULL || info->filesystem != g_package_file) {
157 return NULL;
158 }
159
160 /* Strip the package root off of the path.
161 */
162 size_t root_len = strlen(info->name);
163 root_path += root_len;
164 size_t root_path_len = strlen(root_path);
165
166 if (out_buf_len < root_path_len + 1) {
167 return NULL;
168 }
169 strcpy(out_buf, root_path);
170 *out_package = g_package;
171 return out_buf;
172}
173
174/* Takes a string like "SYSTEM:lib" and turns it into a string
175 * like "/system/lib". The translated path is put in out_buf,
176 * and out_buf is returned if the translation succeeded.
177 */
178const char *
179translate_root_path(const char *root_path, char *out_buf, size_t out_buf_len)
180{
181 if (out_buf_len < 1) {
182 return NULL;
183 }
184
185 const RootInfo *info = get_root_info_for_path(root_path);
186 if (info == NULL || info->mount_point == NULL) {
187 return NULL;
188 }
189
190 /* Find the relative part of the non-root part of the path.
191 */
192 root_path += strlen(info->name); // strip off the "root:"
193 while (*root_path != '\0' && *root_path == '/') {
194 root_path++;
195 }
196
197 size_t mp_len = strlen(info->mount_point);
198 size_t rp_len = strlen(root_path);
199 if (mp_len + 1 + rp_len + 1 > out_buf_len) {
200 return NULL;
201 }
202
203 /* Glue the mount point to the relative part of the path.
204 */
205 memcpy(out_buf, info->mount_point, mp_len);
206 if (out_buf[mp_len - 1] != '/') out_buf[mp_len++] = '/';
207
208 memcpy(out_buf + mp_len, root_path, rp_len);
209 out_buf[mp_len + rp_len] = '\0';
210
211 return out_buf;
212}
213
214static int
215internal_root_mounted(const RootInfo *info)
216{
217 if (info->mount_point == NULL) {
218 return -1;
219 }
220//xxx if TMP: (or similar) just say "yes"
221
222 /* See if this root is already mounted.
223 */
224 int ret = scan_mounted_volumes();
225 if (ret < 0) {
226 return ret;
227 }
228 const MountedVolume *volume;
229 volume = find_mounted_volume_by_mount_point(info->mount_point);
230 if (volume != NULL) {
231 /* It's already mounted.
232 */
233 return 0;
234 }
235 return -1;
236}
237
238int
239is_root_path_mounted(const char *root_path)
240{
241 const RootInfo *info = get_root_info_for_path(root_path);
242 if (info == NULL) {
243 return -1;
244 }
245 return internal_root_mounted(info) >= 0;
246}
247
248int
249ensure_root_path_mounted(const char *root_path)
250{
251 const RootInfo *info = get_root_info_for_path(root_path);
252 if (info == NULL) {
253 return -1;
254 }
255
256 int ret = internal_root_mounted(info);
257 if (ret >= 0) {
258 /* It's already mounted.
259 */
260 return 0;
261 }
262
263 /* It's not mounted.
264 */
265 if (info->device == g_mtd_device) {
266 if (info->partition_name == NULL) {
267 return -1;
268 }
269//TODO: make the mtd stuff scan once when it needs to
270 mtd_scan_partitions();
271 const MtdPartition *partition;
272 partition = mtd_find_partition_by_name(info->partition_name);
273 if (partition == NULL) {
274 return -1;
275 }
276 return mtd_mount_partition(partition, info->mount_point,
277 info->filesystem, 0);
278 }
279
280 if (info->device == NULL || info->mount_point == NULL ||
281 info->filesystem == NULL ||
282 info->filesystem == g_raw ||
283 info->filesystem == g_package_file) {
284 return -1;
285 }
286
287 mkdir(info->mount_point, 0755); // in case it doesn't already exist
288 if (mount(info->device, info->mount_point, info->filesystem,
289 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "")) {
290 if (info->device2 == NULL) {
291 LOGE("Can't mount %s\n(%s)\n", info->device, strerror(errno));
292 return -1;
293 } else if (mount(info->device2, info->mount_point, info->filesystem,
294 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "")) {
295 LOGE("Can't mount %s (or %s)\n(%s)\n",
296 info->device, info->device2, strerror(errno));
297 return -1;
298 }
299 }
300 return 0;
301}
302
303int
304ensure_root_path_unmounted(const char *root_path)
305{
306 const RootInfo *info = get_root_info_for_path(root_path);
307 if (info == NULL) {
308 return -1;
309 }
310 if (info->mount_point == NULL) {
311 /* This root can't be mounted, so by definition it isn't.
312 */
313 return 0;
314 }
315//xxx if TMP: (or similar) just return error
316
317 /* See if this root is already mounted.
318 */
319 int ret = scan_mounted_volumes();
320 if (ret < 0) {
321 return ret;
322 }
323 const MountedVolume *volume;
324 volume = find_mounted_volume_by_mount_point(info->mount_point);
325 if (volume == NULL) {
326 /* It's not mounted.
327 */
328 return 0;
329 }
330
331 return unmount_mounted_volume(volume);
332}
333
334const MtdPartition *
335get_root_mtd_partition(const char *root_path)
336{
337 const RootInfo *info = get_root_info_for_path(root_path);
338 if (info == NULL || info->device != g_mtd_device ||
339 info->partition_name == NULL)
340 {
341 return NULL;
342 }
343 mtd_scan_partitions();
344 return mtd_find_partition_by_name(info->partition_name);
345}
346
347int
348format_root_device(const char *root)
349{
350 /* Be a little safer here; require that "root" is just
351 * a device with no relative path after it.
352 */
353 const char *c = root;
354 while (*c != '\0' && *c != ':') {
355 c++;
356 }
357 if (c[0] != ':' || c[1] != '\0') {
358 LOGW("format_root_device: bad root name \"%s\"\n", root);
359 return -1;
360 }
361
362 const RootInfo *info = get_root_info_for_path(root);
363 if (info == NULL || info->device == NULL) {
364 LOGW("format_root_device: can't resolve \"%s\"\n", root);
365 return -1;
366 }
367 if (info->mount_point != NULL) {
368 /* Don't try to format a mounted device.
369 */
370 int ret = ensure_root_path_unmounted(root);
371 if (ret < 0) {
372 LOGW("format_root_device: can't unmount \"%s\"\n", root);
373 return ret;
374 }
375 }
376
377 /* Format the device.
378 */
379 if (info->device == g_mtd_device) {
380 mtd_scan_partitions();
381 const MtdPartition *partition;
382 partition = mtd_find_partition_by_name(info->partition_name);
383 if (partition == NULL) {
384 LOGW("format_root_device: can't find mtd partition \"%s\"\n",
385 info->partition_name);
386 return -1;
387 }
388 if (info->filesystem == g_raw || !strcmp(info->filesystem, "yaffs2")) {
389 MtdWriteContext *write = mtd_write_partition(partition);
390 if (write == NULL) {
391 LOGW("format_root_device: can't open \"%s\"\n", root);
392 return -1;
393 } else if (mtd_erase_blocks(write, -1) == (off_t) -1) {
394 LOGW("format_root_device: can't erase \"%s\"\n", root);
395 mtd_write_close(write);
396 return -1;
397 } else if (mtd_write_close(write)) {
398 LOGW("format_root_device: can't close \"%s\"\n", root);
399 return -1;
400 } else {
401 return 0;
402 }
403 }
404 }
Koushik Dutta2f73e582010-04-18 16:00:21 -0700405
406 return format_non_mtd_device(root);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800407}