• 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     { "MBM:", g_mtd_device, NULL, "mbm", NULL, g_raw },
56     { "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 
62 static const RootInfo *
get_root_info_for_path(const char * root_path)63 get_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 
87 static const ZipArchive *g_package = NULL;
88 static char *g_package_path = NULL;
89 
90 int
register_package_root(const ZipArchive * package,const char * package_path)91 register_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 
107 int
is_package_root_path(const char * root_path)108 is_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 
114 const char *
translate_package_root_path(const char * root_path,char * out_buf,size_t out_buf_len,const ZipArchive ** out_package)115 translate_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  */
141 const char *
translate_root_path(const char * root_path,char * out_buf,size_t out_buf_len)142 translate_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 
177 static int
internal_root_mounted(const RootInfo * info)178 internal_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 
201 int
is_root_path_mounted(const char * root_path)202 is_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 
211 int
ensure_root_path_mounted(const char * root_path)212 ensure_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 
266 int
ensure_root_path_unmounted(const char * root_path)267 ensure_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 
297 const MtdPartition *
get_root_mtd_partition(const char * root_path)298 get_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 
310 int
format_root_device(const char * root)311 format_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 }
372