• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
30 typedef 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.
40 xxx may just want to use enums
41  */
42 static const char g_mtd_device[] = "@\0g_mtd_device";
43 static const char g_raw[] = "@\0g_raw";
44 static const char g_package_file[] = "@\0g_package_file";
45 
46 static 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" },
55     { "TMP:", NULL, NULL, NULL, "/tmp", NULL },
56 };
57 #define NUM_ROOTS (sizeof(g_roots) / sizeof(g_roots[0]))
58 
59 // TODO: for SDCARD:, try /dev/block/mmcblk0 if mmcblk0p1 fails
60 
61 static const RootInfo *
get_root_info_for_path(const char * root_path)62 get_root_info_for_path(const char *root_path)
63 {
64     const char *c;
65 
66     /* Find the first colon.
67      */
68     c = root_path;
69     while (*c != '\0' && *c != ':') {
70         c++;
71     }
72     if (*c == '\0') {
73         return NULL;
74     }
75     size_t len = c - root_path + 1;
76     size_t i;
77     for (i = 0; i < NUM_ROOTS; i++) {
78         RootInfo *info = &g_roots[i];
79         if (strncmp(info->name, root_path, len) == 0) {
80             return info;
81         }
82     }
83     return NULL;
84 }
85 
86 static const ZipArchive *g_package = NULL;
87 static char *g_package_path = NULL;
88 
89 int
register_package_root(const ZipArchive * package,const char * package_path)90 register_package_root(const ZipArchive *package, const char *package_path)
91 {
92     if (package != NULL) {
93         package_path = strdup(package_path);
94         if (package_path == NULL) {
95             return -1;
96         }
97         g_package_path = (char *)package_path;
98     } else {
99         free(g_package_path);
100         g_package_path = NULL;
101     }
102     g_package = package;
103     return 0;
104 }
105 
106 int
is_package_root_path(const char * root_path)107 is_package_root_path(const char *root_path)
108 {
109     const RootInfo *info = get_root_info_for_path(root_path);
110     return info != NULL && info->filesystem == g_package_file;
111 }
112 
113 const char *
translate_package_root_path(const char * root_path,char * out_buf,size_t out_buf_len,const ZipArchive ** out_package)114 translate_package_root_path(const char *root_path,
115         char *out_buf, size_t out_buf_len, const ZipArchive **out_package)
116 {
117     const RootInfo *info = get_root_info_for_path(root_path);
118     if (info == NULL || info->filesystem != g_package_file) {
119         return NULL;
120     }
121 
122     /* Strip the package root off of the path.
123      */
124     size_t root_len = strlen(info->name);
125     root_path += root_len;
126     size_t root_path_len = strlen(root_path);
127 
128     if (out_buf_len < root_path_len + 1) {
129         return NULL;
130     }
131     strcpy(out_buf, root_path);
132     *out_package = g_package;
133     return out_buf;
134 }
135 
136 /* Takes a string like "SYSTEM:lib" and turns it into a string
137  * like "/system/lib".  The translated path is put in out_buf,
138  * and out_buf is returned if the translation succeeded.
139  */
140 const char *
translate_root_path(const char * root_path,char * out_buf,size_t out_buf_len)141 translate_root_path(const char *root_path, char *out_buf, size_t out_buf_len)
142 {
143     if (out_buf_len < 1) {
144         return NULL;
145     }
146 
147     const RootInfo *info = get_root_info_for_path(root_path);
148     if (info == NULL || info->mount_point == NULL) {
149         return NULL;
150     }
151 
152     /* Find the relative part of the non-root part of the path.
153      */
154     root_path += strlen(info->name);  // strip off the "root:"
155     while (*root_path != '\0' && *root_path == '/') {
156         root_path++;
157     }
158 
159     size_t mp_len = strlen(info->mount_point);
160     size_t rp_len = strlen(root_path);
161     if (mp_len + 1 + rp_len + 1 > out_buf_len) {
162         return NULL;
163     }
164 
165     /* Glue the mount point to the relative part of the path.
166      */
167     memcpy(out_buf, info->mount_point, mp_len);
168     if (out_buf[mp_len - 1] != '/') out_buf[mp_len++] = '/';
169 
170     memcpy(out_buf + mp_len, root_path, rp_len);
171     out_buf[mp_len + rp_len] = '\0';
172 
173     return out_buf;
174 }
175 
176 static int
internal_root_mounted(const RootInfo * info)177 internal_root_mounted(const RootInfo *info)
178 {
179     if (info->mount_point == NULL) {
180         return -1;
181     }
182 //xxx if TMP: (or similar) just say "yes"
183 
184     /* See if this root is already mounted.
185      */
186     int ret = scan_mounted_volumes();
187     if (ret < 0) {
188         return ret;
189     }
190     const MountedVolume *volume;
191     volume = find_mounted_volume_by_mount_point(info->mount_point);
192     if (volume != NULL) {
193         /* It's already mounted.
194          */
195         return 0;
196     }
197     return -1;
198 }
199 
200 int
is_root_path_mounted(const char * root_path)201 is_root_path_mounted(const char *root_path)
202 {
203     const RootInfo *info = get_root_info_for_path(root_path);
204     if (info == NULL) {
205         return -1;
206     }
207     return internal_root_mounted(info) >= 0;
208 }
209 
210 int
ensure_root_path_mounted(const char * root_path)211 ensure_root_path_mounted(const char *root_path)
212 {
213     const RootInfo *info = get_root_info_for_path(root_path);
214     if (info == NULL) {
215         return -1;
216     }
217 
218     int ret = internal_root_mounted(info);
219     if (ret >= 0) {
220         /* It's already mounted.
221          */
222         return 0;
223     }
224 
225     /* It's not mounted.
226      */
227     if (info->device == g_mtd_device) {
228         if (info->partition_name == NULL) {
229             return -1;
230         }
231 //TODO: make the mtd stuff scan once when it needs to
232         mtd_scan_partitions();
233         const MtdPartition *partition;
234         partition = mtd_find_partition_by_name(info->partition_name);
235         if (partition == NULL) {
236             return -1;
237         }
238         return mtd_mount_partition(partition, info->mount_point,
239                 info->filesystem, 0);
240     }
241 
242     if (info->device == NULL || info->mount_point == NULL ||
243         info->filesystem == NULL ||
244         info->filesystem == g_raw ||
245         info->filesystem == g_package_file) {
246         return -1;
247     }
248 
249     mkdir(info->mount_point, 0755);  // in case it doesn't already exist
250     if (mount(info->device, info->mount_point, info->filesystem,
251             MS_NOATIME | MS_NODEV | MS_NODIRATIME, "")) {
252         if (info->device2 == NULL) {
253             LOGE("Can't mount %s\n(%s)\n", info->device, strerror(errno));
254             return -1;
255         } else if (mount(info->device2, info->mount_point, info->filesystem,
256                 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "")) {
257             LOGE("Can't mount %s (or %s)\n(%s)\n",
258                     info->device, info->device2, strerror(errno));
259             return -1;
260         }
261     }
262     return 0;
263 }
264 
265 int
ensure_root_path_unmounted(const char * root_path)266 ensure_root_path_unmounted(const char *root_path)
267 {
268     const RootInfo *info = get_root_info_for_path(root_path);
269     if (info == NULL) {
270         return -1;
271     }
272     if (info->mount_point == NULL) {
273         /* This root can't be mounted, so by definition it isn't.
274          */
275         return 0;
276     }
277 //xxx if TMP: (or similar) just return error
278 
279     /* See if this root is already mounted.
280      */
281     int ret = scan_mounted_volumes();
282     if (ret < 0) {
283         return ret;
284     }
285     const MountedVolume *volume;
286     volume = find_mounted_volume_by_mount_point(info->mount_point);
287     if (volume == NULL) {
288         /* It's not mounted.
289          */
290         return 0;
291     }
292 
293     return unmount_mounted_volume(volume);
294 }
295 
296 const MtdPartition *
get_root_mtd_partition(const char * root_path)297 get_root_mtd_partition(const char *root_path)
298 {
299     const RootInfo *info = get_root_info_for_path(root_path);
300     if (info == NULL || info->device != g_mtd_device ||
301             info->partition_name == NULL)
302     {
303         return NULL;
304     }
305     mtd_scan_partitions();
306     return mtd_find_partition_by_name(info->partition_name);
307 }
308 
309 int
format_root_device(const char * root)310 format_root_device(const char *root)
311 {
312     /* Be a little safer here; require that "root" is just
313      * a device with no relative path after it.
314      */
315     const char *c = root;
316     while (*c != '\0' && *c != ':') {
317         c++;
318     }
319     if (c[0] != ':' || c[1] != '\0') {
320         LOGW("format_root_device: bad root name \"%s\"\n", root);
321         return -1;
322     }
323 
324     const RootInfo *info = get_root_info_for_path(root);
325     if (info == NULL || info->device == NULL) {
326         LOGW("format_root_device: can't resolve \"%s\"\n", root);
327         return -1;
328     }
329     if (info->mount_point != NULL) {
330         /* Don't try to format a mounted device.
331          */
332         int ret = ensure_root_path_unmounted(root);
333         if (ret < 0) {
334             LOGW("format_root_device: can't unmount \"%s\"\n", root);
335             return ret;
336         }
337     }
338 
339     /* Format the device.
340      */
341     if (info->device == g_mtd_device) {
342         mtd_scan_partitions();
343         const MtdPartition *partition;
344         partition = mtd_find_partition_by_name(info->partition_name);
345         if (partition == NULL) {
346             LOGW("format_root_device: can't find mtd partition \"%s\"\n",
347                     info->partition_name);
348             return -1;
349         }
350         if (info->filesystem == g_raw || !strcmp(info->filesystem, "yaffs2")) {
351             MtdWriteContext *write = mtd_write_partition(partition);
352             if (write == NULL) {
353                 LOGW("format_root_device: can't open \"%s\"\n", root);
354                 return -1;
355             } else if (mtd_erase_blocks(write, -1) == (off_t) -1) {
356                 LOGW("format_root_device: can't erase \"%s\"\n", root);
357                 mtd_write_close(write);
358                 return -1;
359             } else if (mtd_write_close(write)) {
360                 LOGW("format_root_device: can't close \"%s\"\n", root);
361                 return -1;
362             } else {
363                 return 0;
364             }
365         }
366     }
367 //TODO: handle other device types (sdcard, etc.)
368     LOGW("format_root_device: can't handle non-mtd device \"%s\"\n", root);
369     return -1;
370 }
371