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 <string.h>
20 #include <sys/mount.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include <ctype.h>
25
26 #include "mtdutils/mtdutils.h"
27 #include "mtdutils/mounts.h"
28 #include "roots.h"
29 #include "common.h"
30 #include "rktools.h"
31 #include "mtdutils/rk29.h"
32
33 static int num_volumes = 0;
34 static Volume* device_volumes = NULL;
35 static char mount_point[256] = {0};
36
37 #define VOLUME_TO_LABEL(v) ((strrchr(v->mount_point, '/') ? : "/unknown") + 1)
38
get_link_path(const char * linkpath,char * buf,int count)39 char * get_link_path(const char* linkpath, char * buf, int count)
40 {
41 int i;
42 int rslt;
43 char path[256];
44
45 memset(path, 0, sizeof(path));
46 strcpy(path, linkpath);
47 for (i = strlen(linkpath); i > 0; i--) {
48 if (path[i] == '/') {
49 path[i] = '\0';
50 break;
51 }
52 }
53
54 rslt = readlink(path, buf, count - 1);
55 if (rslt < 0 || (rslt >= count - 1)) {
56 // printf("No link to path [%s]!!! \n", path);
57 return NULL;
58 }
59
60 if (buf[0] != '/') {
61 char tmp[256];
62 memset(tmp, 0, sizeof(tmp));
63 memcpy(tmp, buf, strlen(buf));
64
65 memset(buf, 0, sizeof(buf));
66 memcpy(buf + 1, tmp, strlen(tmp));
67
68 buf[0] = '/';
69 }
70
71 // printf("buf = %s \n", buf);
72 return buf;
73 }
74
get_mounted_device_from_path(const char * path)75 const char* get_mounted_device_from_path(const char* path)
76 {
77 const MountedVolume *volume;
78
79 int result = scan_mounted_volumes();
80 if (result < 0) {
81 LOGE("failed to scan mounted volumes\n");
82 return NULL;
83 }
84
85 volume = find_mounted_volume_by_mount_point(path);
86 if (!volume) {
87 LOGE("failed to get volume from %s\n", path);
88 return NULL;
89 }
90
91 return volume->device;
92 }
93
load_volume_table()94 void load_volume_table()
95 {
96 int alloc = 2;
97 device_volumes = malloc(alloc * sizeof(Volume));
98
99 // Insert an entry for /tmp, which is the ramdisk and is always mounted.
100 device_volumes[0].mount_point = "/tmp";
101 device_volumes[0].fs_type = "ramdisk";
102 device_volumes[0].device = NULL;
103 device_volumes[0].device2 = NULL;
104 device_volumes[0].option = NULL;
105 device_volumes[0].dump = NULL;
106 device_volumes[0].pass = NULL;
107 num_volumes = 1;
108
109 FILE* fstab = fopen("/etc/fstab", "r");
110 if (fstab == NULL) {
111 LOGE("failed to open /etc/fstab (%d)\n", errno);
112 return;
113 }
114
115 char buffer[1024];
116 char file_system[1024];
117 char mount_point[1024];
118 char fs_type[1024];
119 char option[1024];
120 char dump[1024];
121 char pass[1024];
122 char device[1024];
123 int i;
124 while (fgets(buffer, sizeof(buffer) - 1, fstab)) {
125 i = sscanf(buffer, "%s %s %s %s %s %s", file_system,
126 mount_point, fs_type, option, dump, pass);
127 if (file_system[0] == '#') continue;
128 //printf("load_volume_table file_system:%s, mount_point:%s, fs_type:%s, option:%s, dump:%s, pass:%s\n", file_system, mount_point, fs_type, option, dump, pass);
129 /* HACK: Convert *LABEL to "by-name" symlink */
130 if (strstr(file_system, "LABEL="))
131 snprintf(device, sizeof(device), "/dev/block/by-name/%s",
132 strstr(file_system, "LABEL=") + strlen("LABEL="));
133 else
134 strcpy(device, file_system);
135
136 if (i == 6) {
137 while (num_volumes >= alloc) {
138 alloc *= 2;
139 device_volumes = realloc(device_volumes, alloc * sizeof(Volume));
140 }
141 device_volumes[num_volumes].mount_point = strdup(mount_point);
142 device_volumes[num_volumes].fs_type = strdup(fs_type);
143 device_volumes[num_volumes].option = strdup(option);
144 device_volumes[num_volumes].dump = strdup(dump);
145 device_volumes[num_volumes].pass = strdup(pass);
146 device_volumes[num_volumes].device = strdup(device);;
147 device_volumes[num_volumes].device2 = NULL;
148 ++num_volumes;
149 } else {
150 LOGE("skipping malformed recovery.fstab line: %s\n", buffer);
151 }
152 }
153
154 fclose(fstab);
155
156 printf("recovery filesystem table\n");
157 printf("=========================\n");
158 for (i = 0; i < num_volumes; ++i) {
159 Volume* v = &device_volumes[i];
160 printf(" %d %s %s %s %s %s %s\n", i, v->device, v->mount_point, v->fs_type, v->option, v->dump, v->pass);
161 }
162 printf("\n");
163 }
164
volume_for_path(const char * path)165 Volume* volume_for_path(const char* path)
166 {
167 int i;
168
169 memset(mount_point, 0, sizeof(mount_point));
170 char* tmp = get_link_path(path, mount_point, 1024);
171
172 // if ( tmp != NULL)
173 // printf(" ### get mount_ponit = %s ### \n", mount_point);
174
175 for (i = 0; i < num_volumes; ++i) {
176 Volume* v = device_volumes + i;
177 int len = strlen(v->mount_point);
178 if (strncmp(path, v->mount_point, len) == 0 &&
179 (path[len] == '\0' || path[len] == '/')) {
180 //printf(" ===path = %s, v-mount_point = %s ===\n",path, v->mount_point);
181 return v;
182 } else {
183 //add by chad.ma for symbol link file. eg. sdcard/ --->mnt/sdcard
184 if (!tmp)
185 continue;
186
187 //printf(" # v->mount_point = %s\n", v->mount_point);
188 if (strncmp(mount_point, v->mount_point, len) == 0 &&
189 (path[len] == '\0' || path[len] == '/')) {
190 return v;
191 }
192 }
193 }
194 return NULL;
195 }
196
ensure_path_mounted(const char * path)197 int ensure_path_mounted(const char* path)
198 {
199 if (access(path, F_OK) == 0)
200 return 0;
201
202 Volume* v = volume_for_path(path);
203 if (v == NULL) {
204 if (mount_point[0] != 0) {
205 int result = scan_mounted_volumes();
206 if (result < 0) {
207 LOGE("failed to scan mounted volumes\n");
208 return -1;
209 }
210
211 const MountedVolume* mv =
212 find_mounted_volume_by_mount_point(mount_point);
213 if (mv) {
214 // volume is already mounted
215 LOGI("%s already mounted \n", path);
216 return 0;
217 }
218 }
219
220 LOGE("unknown volume for path [%s]\n", path);
221 return -1;
222 }
223 if (strcmp(v->fs_type, "ramdisk") == 0) {
224 // the ramdisk is always mounted.
225 return 0;
226 }
227
228 int result;
229 result = scan_mounted_volumes();
230 if (result < 0) {
231 LOGE("failed to scan mounted volumes\n");
232 return -1;
233 }
234
235 const MountedVolume* mv =
236 find_mounted_volume_by_mount_point(v->mount_point);
237 if (mv) {
238 // volume is already mounted
239 return 0;
240 }
241
242 mkdir(v->mount_point, 0755); // in case it doesn't already exist
243
244 if (strcmp(v->fs_type, "yaffs2") == 0) {
245 // mount an MTD partition as a YAFFS2 filesystem.
246 mtd_scan_partitions();
247 const MtdPartition* partition;
248 partition = mtd_find_partition_by_name(v->device);
249 if (partition == NULL) {
250 LOGE("failed to find \"%s\" partition to mount at \"%s\"\n",
251 v->device, v->mount_point);
252 return -1;
253 }
254 return mtd_mount_partition(partition, v->mount_point, v->fs_type, 0);
255 } else if (strcmp(v->fs_type, "ext4") == 0 ||
256 strcmp(v->fs_type, "vfat") == 0 ||
257 strcmp(v->fs_type, "ext2") == 0) {
258 char *blk_device;
259 blk_device = (char*)v->device;
260 if (strcmp("/mnt/sdcard", v->mount_point) == 0) {
261 blk_device = getenv(SD_POINT_NAME);
262 if (blk_device == NULL) {
263 setFlashPoint();
264 blk_device = getenv(SD_POINT_NAME);
265 }
266 result = mount(blk_device, v->mount_point, v->fs_type,
267 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "");
268 if (result == 0) return 0;
269 }
270 result = mount(v->device, v->mount_point, v->fs_type,
271 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "");
272 if (result == 0) return 0;
273
274 if (v->device2) {
275 LOGW("failed to mount %s (%s); trying %s\n",
276 v->device, strerror(errno), v->device2);
277 result = mount(v->device2, v->mount_point, v->fs_type,
278 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "");
279 if (result == 0) return 0;
280 }
281 LOGE("failed to mount %s (%s)\n", v->mount_point, strerror(errno));
282 return -1;
283 }
284
285 LOGE("unknown fs_type \"%s\" for %s\n", v->fs_type, v->mount_point);
286 return -1;
287 }
288
ensure_ex_path_unmounted(const char * path)289 int ensure_ex_path_unmounted(const char* path)
290 {
291 int result;
292
293 result = scan_mounted_volumes();
294 if (result < 0) {
295 LOGE("unknown volume for path [%s]\n", path);
296 return -1;
297 }
298
299 const MountedVolume* mv =
300 find_mounted_volume_by_mount_point(path);
301 if (mv == NULL) {
302 LOGE("path: %s is already unmounted or not existed\n");
303 return 0;
304 }
305
306 return unmount_mounted_volume(mv);
307 }
308
ensure_path_unmounted(const char * path)309 int ensure_path_unmounted(const char* path)
310 {
311 Volume* v = volume_for_path(path);
312 if (v == NULL) {
313 LOGE("unknown volume for path [%s]\n", path);
314 return -1;
315 }
316 if (strcmp(v->fs_type, "ramdisk") == 0) {
317 // the ramdisk is always mounted; you can't unmount it.
318 return -1;
319 }
320
321 int result;
322 result = scan_mounted_volumes();
323 if (result < 0) {
324 LOGE("failed to scan mounted volumes\n");
325 return -1;
326 }
327
328 const MountedVolume* mv =
329 find_mounted_volume_by_mount_point(v->mount_point);
330 if (mv == NULL) {
331 // volume is already unmounted
332 return 0;
333 }
334
335 return unmount_mounted_volume(mv);
336 }
337
format_volume(const char * volume)338 int format_volume(const char* volume)
339 {
340 Volume* v = volume_for_path(volume);
341 const char *label;
342
343 if (v == NULL) {
344 LOGE("unknown volume \"%s\"\n", volume);
345 return -1;
346 }
347 if (strcmp(v->fs_type, "ramdisk") == 0) {
348 // you can't format the ramdisk.
349 LOGE("can't format_volume \"%s\"", volume);
350 return -1;
351 }
352 if (strcmp(v->mount_point, volume) != 0) {
353 LOGE("can't give path \"%s\" to format_volume\n", volume);
354 return -1;
355 }
356
357 if (ensure_path_unmounted(volume) != 0) {
358 LOGE("format_volume failed to unmount \"%s\"\n", v->mount_point);
359 return -1;
360 }
361
362 label = VOLUME_TO_LABEL(v);
363
364 if (strcmp(v->fs_type, "yaffs2") == 0 || strcmp(v->fs_type, "mtd") == 0 || strcmp(v->fs_type, "ubifs") == 0 ) {
365 mtd_scan_partitions();
366 char filepath[20];
367 if (strstr(v->device, "userdata") != NULL) {
368 strcpy(filepath, "userdata");
369 LOGW("change v->device from %s to %s.\n", v->device, filepath);
370 } else {
371 strcpy(filepath, v->device);
372 }
373
374 const MtdPartition* partition = mtd_find_partition_by_name(filepath);
375 if (partition == NULL) {
376 LOGE("format_volume: no MTD partition \"%s\"\n", v->device);
377 return -1;
378 }
379
380 MtdWriteContext *write = mtd_write_partition(partition);
381 if (write == NULL) {
382 LOGW("format_volume: can't open MTD \"%s\"\n", v->device);
383 return -1;
384 } else if (mtd_erase_blocks(write, -1) == (off_t) -1) {
385 LOGW("format_volume: can't erase MTD \"%s\"\n", v->device);
386 mtd_write_close(write);
387 return -1;
388 } else if (mtd_write_close(write)) {
389 LOGW("format_volume: can't close MTD \"%s\"\n", v->device);
390 return -1;
391 }
392 return 0;
393 }
394
395 if (strcmp(v->fs_type, "ext4") == 0) {
396 int result = make_ext4(v->device, label);
397 if (result != 0) {
398 LOGE("format_volume: make_extf4 failed on %s\n", v->device);
399 return -1;
400 }
401 return 0;
402 }
403
404 if (strcmp(v->fs_type, "ext2") == 0) {
405 int result = make_ext2(v->device, label);
406 if (result != 0) {
407 LOGE("format_volume: make_extf2 failed on %s\n", v->device);
408 return -1;
409 }
410 return 0;
411 }
412 if (strcmp(v->fs_type, "vfat") == 0) {
413 int result = make_vfat(v->device, label);
414 if (result != 0) {
415 LOGE("format_volume: make_vfat failed on %s\n", v->device);
416 return -1;
417 }
418 return 0;
419 }
420
421 if (strcmp(v->fs_type, "ntfs") == 0) {
422 int result = make_ntfs(v->device, label);
423 if (result != 0) {
424 LOGE("format_volume: make_ntfs failed on %s\n", v->device);
425 return -1;
426 }
427 return 0;
428 }
429
430 LOGE("format_volume: fs_type \"%s\" unsupported\n", v->fs_type);
431 return -1;
432 }
433
resize_volume(const char * volume)434 int resize_volume(const char* volume)
435 {
436 Volume* v = volume_for_path(volume);
437 if (v == NULL) {
438 LOGE("unknown volume \"%s\"\n", volume);
439 return -1;
440 }
441 if (strcmp(v->fs_type, "ramdisk") == 0) {
442 // you can't format the ramdisk.
443 LOGE("can't format_volume \"%s\"", volume);
444 return -1;
445 }
446 if (strcmp(v->mount_point, volume) != 0) {
447 LOGE("can't give path \"%s\" to format_volume\n", volume);
448 return -1;
449 }
450
451 if (ensure_path_unmounted(volume) != 0) {
452 LOGE("format_volume failed to unmount \"%s\"\n", v->mount_point);
453 return -1;
454 }
455
456 if ((strcmp(v->fs_type, "ext4") == 0) || (strcmp(v->fs_type, "ext2") == 0)) {
457 int result = rk_check_and_resizefs(v->device);
458 if (result != 0) {
459 LOGE("resize_volume: resizefs failed on %s\n", v->device);
460 return -1;
461 }
462 return 0;
463 }
464
465 LOGE("format_volume: fs_type \"%s\" unsupported\n", v->fs_type);
466 return -1;
467 }
468
469