blob: 8f8dacebfd81d6bb8d214333a7ffd6f7a305e85d [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
30typedef struct {
31 const char *name;
32 const char *device;
33 const char *device2; // If the first one doesn't work (may be NULL)
34 const char *partition_name;
35 const char *mount_point;
36 const char *filesystem;
37} RootInfo;
38
39/* Canonical pointers.
40xxx may just want to use enums
41 */
42static const char g_mtd_device[] = "@\0g_mtd_device";
43static const char g_raw[] = "@\0g_raw";
44static const char g_package_file[] = "@\0g_package_file";
45
46static RootInfo g_roots[] = {
47 { "BOOT:", g_mtd_device, NULL, "boot", NULL, g_raw },
48 { "CACHE:", g_mtd_device, NULL, "cache", "/cache", "yaffs2" },
49 { "DATA:", g_mtd_device, NULL, "userdata", "/data", "yaffs2" },
50 { "MISC:", g_mtd_device, NULL, "misc", NULL, g_raw },
51 { "PACKAGE:", NULL, NULL, NULL, NULL, g_package_file },
52 { "RECOVERY:", g_mtd_device, NULL, "recovery", "/", g_raw },
53 { "SDCARD:", "/dev/block/mmcblk0p1", "/dev/block/mmcblk0", NULL, "/sdcard", "vfat" },
54 { "SYSTEM:", g_mtd_device, NULL, "system", "/system", "yaffs2" },
Doug Zongkerb128f542009-06-18 15:07:14 -070055 { "MBM:", g_mtd_device, NULL, "mbm", NULL, g_raw },
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080056 { "TMP:", NULL, NULL, NULL, "/tmp", NULL },
57};
58#define NUM_ROOTS (sizeof(g_roots) / sizeof(g_roots[0]))
59
60// TODO: for SDCARD:, try /dev/block/mmcblk0 if mmcblk0p1 fails
61
62static const RootInfo *
63get_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
211int
212ensure_root_path_mounted(const char *root_path)
213{
214 const RootInfo *info = get_root_info_for_path(root_path);
215 if (info == NULL) {
216 return -1;
217 }
218
219 int ret = internal_root_mounted(info);
220 if (ret >= 0) {
221 /* It's already mounted.
222 */
223 return 0;
224 }
225
226 /* It's not mounted.
227 */
228 if (info->device == g_mtd_device) {
229 if (info->partition_name == NULL) {
230 return -1;
231 }
232//TODO: make the mtd stuff scan once when it needs to
233 mtd_scan_partitions();
234 const MtdPartition *partition;
235 partition = mtd_find_partition_by_name(info->partition_name);
236 if (partition == NULL) {
237 return -1;
238 }
239 return mtd_mount_partition(partition, info->mount_point,
240 info->filesystem, 0);
241 }
242
243 if (info->device == NULL || info->mount_point == NULL ||
244 info->filesystem == NULL ||
245 info->filesystem == g_raw ||
246 info->filesystem == g_package_file) {
247 return -1;
248 }
249
250 mkdir(info->mount_point, 0755); // in case it doesn't already exist
251 if (mount(info->device, info->mount_point, info->filesystem,
252 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "")) {
253 if (info->device2 == NULL) {
254 LOGE("Can't mount %s\n(%s)\n", info->device, strerror(errno));
255 return -1;
256 } else if (mount(info->device2, info->mount_point, info->filesystem,
257 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "")) {
258 LOGE("Can't mount %s (or %s)\n(%s)\n",
259 info->device, info->device2, strerror(errno));
260 return -1;
261 }
262 }
263 return 0;
264}
265
266int
267ensure_root_path_unmounted(const char *root_path)
268{
269 const RootInfo *info = get_root_info_for_path(root_path);
270 if (info == NULL) {
271 return -1;
272 }
273 if (info->mount_point == NULL) {
274 /* This root can't be mounted, so by definition it isn't.
275 */
276 return 0;
277 }
278//xxx if TMP: (or similar) just return error
279
280 /* See if this root is already mounted.
281 */
282 int ret = scan_mounted_volumes();
283 if (ret < 0) {
284 return ret;
285 }
286 const MountedVolume *volume;
287 volume = find_mounted_volume_by_mount_point(info->mount_point);
288 if (volume == NULL) {
289 /* It's not mounted.
290 */
291 return 0;
292 }
293
294 return unmount_mounted_volume(volume);
295}
296
297const MtdPartition *
298get_root_mtd_partition(const char *root_path)
299{
300 const RootInfo *info = get_root_info_for_path(root_path);
301 if (info == NULL || info->device != g_mtd_device ||
302 info->partition_name == NULL)
303 {
304 return NULL;
305 }
306 mtd_scan_partitions();
307 return mtd_find_partition_by_name(info->partition_name);
308}
309
310int
311format_root_device(const char *root)
312{
313 /* Be a little safer here; require that "root" is just
314 * a device with no relative path after it.
315 */
316 const char *c = root;
317 while (*c != '\0' && *c != ':') {
318 c++;
319 }
320 if (c[0] != ':' || c[1] != '\0') {
321 LOGW("format_root_device: bad root name \"%s\"\n", root);
322 return -1;
323 }
324
325 const RootInfo *info = get_root_info_for_path(root);
326 if (info == NULL || info->device == NULL) {
327 LOGW("format_root_device: can't resolve \"%s\"\n", root);
328 return -1;
329 }
330 if (info->mount_point != NULL) {
331 /* Don't try to format a mounted device.
332 */
333 int ret = ensure_root_path_unmounted(root);
334 if (ret < 0) {
335 LOGW("format_root_device: can't unmount \"%s\"\n", root);
336 return ret;
337 }
338 }
339
340 /* Format the device.
341 */
342 if (info->device == g_mtd_device) {
343 mtd_scan_partitions();
344 const MtdPartition *partition;
345 partition = mtd_find_partition_by_name(info->partition_name);
346 if (partition == NULL) {
347 LOGW("format_root_device: can't find mtd partition \"%s\"\n",
348 info->partition_name);
349 return -1;
350 }
351 if (info->filesystem == g_raw || !strcmp(info->filesystem, "yaffs2")) {
352 MtdWriteContext *write = mtd_write_partition(partition);
353 if (write == NULL) {
354 LOGW("format_root_device: can't open \"%s\"\n", root);
355 return -1;
356 } else if (mtd_erase_blocks(write, -1) == (off_t) -1) {
357 LOGW("format_root_device: can't erase \"%s\"\n", root);
358 mtd_write_close(write);
359 return -1;
360 } else if (mtd_write_close(write)) {
361 LOGW("format_root_device: can't close \"%s\"\n", root);
362 return -1;
363 } else {
364 return 0;
365 }
366 }
367 }
368//TODO: handle other device types (sdcard, etc.)
369 LOGW("format_root_device: can't handle non-mtd device \"%s\"\n", root);
370 return -1;
371}