blob: 22988eb5d2073b255db69d6f581dd65ab40ce450 [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
63#ifndef CACHE_DEVICE
64#define CACHE_DEVICE g_mtd_device
65#endif
66
67#ifndef CACHE_FILESYSTEM
68#define CACHE_FILESYSTEM "yaffs2"
Koushik Duttaf8b21c22010-06-14 12:49:47 -070069#endif
70
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080071static RootInfo g_roots[] = {
72 { "BOOT:", g_mtd_device, NULL, "boot", NULL, g_raw },
Koushik Dutta14239d22010-06-14 15:02:48 -070073 { "CACHE:", CACHE_DEVICE, NULL, "cache", "/cache", CACHE_FILESYSTEM },
74 { "DATA:", DATA_DEVICE, NULL, "userdata", "/data", DATA_FILESYSTEM },
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080075 { "MISC:", g_mtd_device, NULL, "misc", NULL, g_raw },
76 { "PACKAGE:", NULL, NULL, NULL, NULL, g_package_file },
77 { "RECOVERY:", g_mtd_device, NULL, "recovery", "/", g_raw },
Koushik Dutta14239d22010-06-14 15:02:48 -070078 { "SDCARD:", SDCARD_DEVICE_PRIMARY, SDCARD_DEVICE_SECONDARY, NULL, "/sdcard", "vfat" },
79 { "SDEXT:", SDEXT_DEVICE, NULL, NULL, "/sd-ext", SDEXT_FILESYSTEM },
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080080 { "SYSTEM:", g_mtd_device, NULL, "system", "/system", "yaffs2" },
Doug Zongkerb128f542009-06-18 15:07:14 -070081 { "MBM:", g_mtd_device, NULL, "mbm", NULL, g_raw },
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080082 { "TMP:", NULL, NULL, NULL, "/tmp", NULL },
83};
84#define NUM_ROOTS (sizeof(g_roots) / sizeof(g_roots[0]))
85
86// TODO: for SDCARD:, try /dev/block/mmcblk0 if mmcblk0p1 fails
87
Koushik Dutta14239d22010-06-14 15:02:48 -070088const RootInfo *
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080089get_root_info_for_path(const char *root_path)
90{
91 const char *c;
92
93 /* Find the first colon.
94 */
95 c = root_path;
96 while (*c != '\0' && *c != ':') {
97 c++;
98 }
99 if (*c == '\0') {
100 return NULL;
101 }
102 size_t len = c - root_path + 1;
103 size_t i;
104 for (i = 0; i < NUM_ROOTS; i++) {
105 RootInfo *info = &g_roots[i];
106 if (strncmp(info->name, root_path, len) == 0) {
107 return info;
108 }
109 }
110 return NULL;
111}
112
113static const ZipArchive *g_package = NULL;
114static char *g_package_path = NULL;
115
116int
117register_package_root(const ZipArchive *package, const char *package_path)
118{
119 if (package != NULL) {
120 package_path = strdup(package_path);
121 if (package_path == NULL) {
122 return -1;
123 }
124 g_package_path = (char *)package_path;
125 } else {
126 free(g_package_path);
127 g_package_path = NULL;
128 }
129 g_package = package;
130 return 0;
131}
132
133int
134is_package_root_path(const char *root_path)
135{
136 const RootInfo *info = get_root_info_for_path(root_path);
137 return info != NULL && info->filesystem == g_package_file;
138}
139
140const char *
141translate_package_root_path(const char *root_path,
142 char *out_buf, size_t out_buf_len, const ZipArchive **out_package)
143{
144 const RootInfo *info = get_root_info_for_path(root_path);
145 if (info == NULL || info->filesystem != g_package_file) {
146 return NULL;
147 }
148
149 /* Strip the package root off of the path.
150 */
151 size_t root_len = strlen(info->name);
152 root_path += root_len;
153 size_t root_path_len = strlen(root_path);
154
155 if (out_buf_len < root_path_len + 1) {
156 return NULL;
157 }
158 strcpy(out_buf, root_path);
159 *out_package = g_package;
160 return out_buf;
161}
162
163/* Takes a string like "SYSTEM:lib" and turns it into a string
164 * like "/system/lib". The translated path is put in out_buf,
165 * and out_buf is returned if the translation succeeded.
166 */
167const char *
168translate_root_path(const char *root_path, char *out_buf, size_t out_buf_len)
169{
170 if (out_buf_len < 1) {
171 return NULL;
172 }
173
174 const RootInfo *info = get_root_info_for_path(root_path);
175 if (info == NULL || info->mount_point == NULL) {
176 return NULL;
177 }
178
179 /* Find the relative part of the non-root part of the path.
180 */
181 root_path += strlen(info->name); // strip off the "root:"
182 while (*root_path != '\0' && *root_path == '/') {
183 root_path++;
184 }
185
186 size_t mp_len = strlen(info->mount_point);
187 size_t rp_len = strlen(root_path);
188 if (mp_len + 1 + rp_len + 1 > out_buf_len) {
189 return NULL;
190 }
191
192 /* Glue the mount point to the relative part of the path.
193 */
194 memcpy(out_buf, info->mount_point, mp_len);
195 if (out_buf[mp_len - 1] != '/') out_buf[mp_len++] = '/';
196
197 memcpy(out_buf + mp_len, root_path, rp_len);
198 out_buf[mp_len + rp_len] = '\0';
199
200 return out_buf;
201}
202
203static int
204internal_root_mounted(const RootInfo *info)
205{
206 if (info->mount_point == NULL) {
207 return -1;
208 }
209//xxx if TMP: (or similar) just say "yes"
210
211 /* See if this root is already mounted.
212 */
213 int ret = scan_mounted_volumes();
214 if (ret < 0) {
215 return ret;
216 }
217 const MountedVolume *volume;
218 volume = find_mounted_volume_by_mount_point(info->mount_point);
219 if (volume != NULL) {
220 /* It's already mounted.
221 */
222 return 0;
223 }
224 return -1;
225}
226
227int
228is_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 return internal_root_mounted(info) >= 0;
235}
236
237int
238ensure_root_path_mounted(const char *root_path)
239{
240 const RootInfo *info = get_root_info_for_path(root_path);
241 if (info == NULL) {
242 return -1;
243 }
244
245 int ret = internal_root_mounted(info);
246 if (ret >= 0) {
247 /* It's already mounted.
248 */
249 return 0;
250 }
251
252 /* It's not mounted.
253 */
254 if (info->device == g_mtd_device) {
255 if (info->partition_name == NULL) {
256 return -1;
257 }
258//TODO: make the mtd stuff scan once when it needs to
259 mtd_scan_partitions();
260 const MtdPartition *partition;
261 partition = mtd_find_partition_by_name(info->partition_name);
262 if (partition == NULL) {
263 return -1;
264 }
265 return mtd_mount_partition(partition, info->mount_point,
266 info->filesystem, 0);
267 }
268
269 if (info->device == NULL || info->mount_point == NULL ||
270 info->filesystem == NULL ||
271 info->filesystem == g_raw ||
272 info->filesystem == g_package_file) {
273 return -1;
274 }
275
276 mkdir(info->mount_point, 0755); // in case it doesn't already exist
277 if (mount(info->device, info->mount_point, info->filesystem,
278 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "")) {
279 if (info->device2 == NULL) {
280 LOGE("Can't mount %s\n(%s)\n", info->device, strerror(errno));
281 return -1;
282 } else if (mount(info->device2, info->mount_point, info->filesystem,
283 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "")) {
284 LOGE("Can't mount %s (or %s)\n(%s)\n",
285 info->device, info->device2, strerror(errno));
286 return -1;
287 }
288 }
289 return 0;
290}
291
292int
293ensure_root_path_unmounted(const char *root_path)
294{
295 const RootInfo *info = get_root_info_for_path(root_path);
296 if (info == NULL) {
297 return -1;
298 }
299 if (info->mount_point == NULL) {
300 /* This root can't be mounted, so by definition it isn't.
301 */
302 return 0;
303 }
304//xxx if TMP: (or similar) just return error
305
306 /* See if this root is already mounted.
307 */
308 int ret = scan_mounted_volumes();
309 if (ret < 0) {
310 return ret;
311 }
312 const MountedVolume *volume;
313 volume = find_mounted_volume_by_mount_point(info->mount_point);
314 if (volume == NULL) {
315 /* It's not mounted.
316 */
317 return 0;
318 }
319
320 return unmount_mounted_volume(volume);
321}
322
323const MtdPartition *
324get_root_mtd_partition(const char *root_path)
325{
326 const RootInfo *info = get_root_info_for_path(root_path);
327 if (info == NULL || info->device != g_mtd_device ||
328 info->partition_name == NULL)
329 {
330 return NULL;
331 }
332 mtd_scan_partitions();
333 return mtd_find_partition_by_name(info->partition_name);
334}
335
336int
337format_root_device(const char *root)
338{
339 /* Be a little safer here; require that "root" is just
340 * a device with no relative path after it.
341 */
342 const char *c = root;
343 while (*c != '\0' && *c != ':') {
344 c++;
345 }
346 if (c[0] != ':' || c[1] != '\0') {
347 LOGW("format_root_device: bad root name \"%s\"\n", root);
348 return -1;
349 }
350
351 const RootInfo *info = get_root_info_for_path(root);
352 if (info == NULL || info->device == NULL) {
353 LOGW("format_root_device: can't resolve \"%s\"\n", root);
354 return -1;
355 }
356 if (info->mount_point != NULL) {
357 /* 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 */
368 if (info->device == g_mtd_device) {
369 mtd_scan_partitions();
370 const MtdPartition *partition;
371 partition = mtd_find_partition_by_name(info->partition_name);
372 if (partition == NULL) {
373 LOGW("format_root_device: can't find mtd partition \"%s\"\n",
374 info->partition_name);
375 return -1;
376 }
377 if (info->filesystem == g_raw || !strcmp(info->filesystem, "yaffs2")) {
378 MtdWriteContext *write = mtd_write_partition(partition);
379 if (write == NULL) {
380 LOGW("format_root_device: can't open \"%s\"\n", root);
381 return -1;
382 } else if (mtd_erase_blocks(write, -1) == (off_t) -1) {
383 LOGW("format_root_device: can't erase \"%s\"\n", root);
384 mtd_write_close(write);
385 return -1;
386 } else if (mtd_write_close(write)) {
387 LOGW("format_root_device: can't close \"%s\"\n", root);
388 return -1;
389 } else {
390 return 0;
391 }
392 }
393 }
Koushik Dutta2f73e582010-04-18 16:00:21 -0700394
395 return format_non_mtd_device(root);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800396}