blob: d7ffb3161908d0b4501d0375f5b3eef647913c15 [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>
Doug Zongkerd4208f92010-09-20 12:16:13 -070023#include <ctype.h>
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080024
Dees_Troy51a0e822012-09-05 15:24:24 -040025extern "C" {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080026#include "mtdutils/mtdutils.h"
27#include "mtdutils/mounts.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040028}
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080029#include "roots.h"
30#include "common.h"
Doug Zongkerd4208f92010-09-20 12:16:13 -070031#include "make_ext4fs.h"
Dees_Troyc51f1f92012-09-20 15:32:13 -040032#include "partitions.hpp"
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080033
Doug Zongkerd4208f92010-09-20 12:16:13 -070034static int num_volumes = 0;
35static Volume* device_volumes = NULL;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080036
Kenny Root41dda822012-03-30 20:48:34 -070037extern struct selabel_handle *sehandle;
Stephen Smalley779701d2012-02-09 14:13:23 -050038
Doug Zongker2810ced2011-02-17 15:55:21 -080039static int parse_options(char* options, Volume* volume) {
40 char* option;
Doug Zongker28ce47c2011-10-28 10:33:05 -070041 while ((option = strtok(options, ","))) {
Doug Zongker2810ced2011-02-17 15:55:21 -080042 options = NULL;
43
Dees_Troy51127312012-09-08 13:08:49 -040044 if (strncmp(option, "flags=", 6) == 0) continue;
45 if (strncmp(option, "length=", 7) == 0) {
Doug Zongker2810ced2011-02-17 15:55:21 -080046 volume->length = strtoll(option+7, NULL, 10);
47 } else {
48 LOGE("bad option \"%s\"\n", option);
49 return -1;
50 }
51 }
52 return 0;
53}
54
Doug Zongkerd4208f92010-09-20 12:16:13 -070055void load_volume_table() {
56 int alloc = 2;
Doug Zongker28ce47c2011-10-28 10:33:05 -070057 device_volumes = (Volume*)malloc(alloc * sizeof(Volume));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080058
Doug Zongkerc18eeb82010-09-21 16:49:26 -070059 // Insert an entry for /tmp, which is the ramdisk and is always mounted.
60 device_volumes[0].mount_point = "/tmp";
61 device_volumes[0].fs_type = "ramdisk";
62 device_volumes[0].device = NULL;
63 device_volumes[0].device2 = NULL;
Doug Zongker2810ced2011-02-17 15:55:21 -080064 device_volumes[0].length = 0;
Doug Zongkerc18eeb82010-09-21 16:49:26 -070065 num_volumes = 1;
66
Doug Zongkerd4208f92010-09-20 12:16:13 -070067 FILE* fstab = fopen("/etc/recovery.fstab", "r");
68 if (fstab == NULL) {
69 LOGE("failed to open /etc/recovery.fstab (%s)\n", strerror(errno));
70 return;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080071 }
Doug Zongkerd4208f92010-09-20 12:16:13 -070072
73 char buffer[1024];
74 int i;
75 while (fgets(buffer, sizeof(buffer)-1, fstab)) {
76 for (i = 0; buffer[i] && isspace(buffer[i]); ++i);
77 if (buffer[i] == '\0' || buffer[i] == '#') continue;
78
79 char* original = strdup(buffer);
80
81 char* mount_point = strtok(buffer+i, " \t\n");
82 char* fs_type = strtok(NULL, " \t\n");
83 char* device = strtok(NULL, " \t\n");
84 // lines may optionally have a second device, to use if
85 // mounting the first one fails.
Doug Zongker2810ced2011-02-17 15:55:21 -080086 char* options = NULL;
Doug Zongkerd4208f92010-09-20 12:16:13 -070087 char* device2 = strtok(NULL, " \t\n");
Doug Zongker2810ced2011-02-17 15:55:21 -080088 if (device2) {
89 if (device2[0] == '/') {
90 options = strtok(NULL, " \t\n");
91 } else {
92 options = device2;
93 device2 = NULL;
94 }
95 }
Doug Zongkerd4208f92010-09-20 12:16:13 -070096
97 if (mount_point && fs_type && device) {
98 while (num_volumes >= alloc) {
99 alloc *= 2;
Doug Zongker28ce47c2011-10-28 10:33:05 -0700100 device_volumes = (Volume*)realloc(device_volumes, alloc*sizeof(Volume));
Doug Zongkerd4208f92010-09-20 12:16:13 -0700101 }
102 device_volumes[num_volumes].mount_point = strdup(mount_point);
103 device_volumes[num_volumes].fs_type = strdup(fs_type);
104 device_volumes[num_volumes].device = strdup(device);
105 device_volumes[num_volumes].device2 =
106 device2 ? strdup(device2) : NULL;
Doug Zongker2810ced2011-02-17 15:55:21 -0800107
108 device_volumes[num_volumes].length = 0;
109 if (parse_options(options, device_volumes + num_volumes) != 0) {
110 LOGE("skipping malformed recovery.fstab line: %s\n", original);
111 } else {
112 ++num_volumes;
113 }
Doug Zongkerd4208f92010-09-20 12:16:13 -0700114 } else {
115 LOGE("skipping malformed recovery.fstab line: %s\n", original);
116 }
117 free(original);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800118 }
Doug Zongkerd4208f92010-09-20 12:16:13 -0700119
120 fclose(fstab);
121
122 printf("recovery filesystem table\n");
123 printf("=========================\n");
124 for (i = 0; i < num_volumes; ++i) {
125 Volume* v = &device_volumes[i];
Doug Zongker2810ced2011-02-17 15:55:21 -0800126 printf(" %d %s %s %s %s %lld\n", i, v->mount_point, v->fs_type,
127 v->device, v->device2, v->length);
Doug Zongkerd4208f92010-09-20 12:16:13 -0700128 }
129 printf("\n");
130}
131
132Volume* volume_for_path(const char* path) {
133 int i;
134 for (i = 0; i < num_volumes; ++i) {
135 Volume* v = device_volumes+i;
136 int len = strlen(v->mount_point);
137 if (strncmp(path, v->mount_point, len) == 0 &&
138 (path[len] == '\0' || path[len] == '/')) {
139 return v;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800140 }
141 }
142 return NULL;
143}
144
Doug Zongkerd4208f92010-09-20 12:16:13 -0700145int ensure_path_mounted(const char* path) {
Dees_Troyc51f1f92012-09-20 15:32:13 -0400146 if (PartitionManager.Mount_By_Path(path, true))
147 return 0;
148 else
149 return -1;
Doug Zongkerd4208f92010-09-20 12:16:13 -0700150 Volume* v = volume_for_path(path);
151 if (v == NULL) {
152 LOGE("unknown volume for path [%s]\n", path);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800153 return -1;
154 }
Doug Zongkerc18eeb82010-09-21 16:49:26 -0700155 if (strcmp(v->fs_type, "ramdisk") == 0) {
156 // the ramdisk is always mounted.
157 return 0;
158 }
Doug Zongkerd4208f92010-09-20 12:16:13 -0700159
160 int result;
161 result = scan_mounted_volumes();
162 if (result < 0) {
163 LOGE("failed to scan mounted volumes\n");
164 return -1;
Doug Zongker23ceeea2010-07-08 17:27:55 -0700165 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800166
Doug Zongkerd4208f92010-09-20 12:16:13 -0700167 const MountedVolume* mv =
168 find_mounted_volume_by_mount_point(v->mount_point);
169 if (mv) {
170 // volume is already mounted
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800171 return 0;
172 }
Doug Zongkerd4208f92010-09-20 12:16:13 -0700173
174 mkdir(v->mount_point, 0755); // in case it doesn't already exist
175
176 if (strcmp(v->fs_type, "yaffs2") == 0) {
177 // mount an MTD partition as a YAFFS2 filesystem.
178 mtd_scan_partitions();
179 const MtdPartition* partition;
180 partition = mtd_find_partition_by_name(v->device);
181 if (partition == NULL) {
182 LOGE("failed to find \"%s\" partition to mount at \"%s\"\n",
183 v->device, v->mount_point);
184 return -1;
185 }
186 return mtd_mount_partition(partition, v->mount_point, v->fs_type, 0);
187 } else if (strcmp(v->fs_type, "ext4") == 0 ||
188 strcmp(v->fs_type, "vfat") == 0) {
189 result = mount(v->device, v->mount_point, v->fs_type,
Doug Zongker469243e2011-04-12 09:28:10 -0700190 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "");
Doug Zongkerd4208f92010-09-20 12:16:13 -0700191 if (result == 0) return 0;
192
193 if (v->device2) {
194 LOGW("failed to mount %s (%s); trying %s\n",
195 v->device, strerror(errno), v->device2);
196 result = mount(v->device2, v->mount_point, v->fs_type,
Doug Zongker469243e2011-04-12 09:28:10 -0700197 MS_NOATIME | MS_NODEV | MS_NODIRATIME, "");
Doug Zongkerd4208f92010-09-20 12:16:13 -0700198 if (result == 0) return 0;
199 }
200
201 LOGE("failed to mount %s (%s)\n", v->mount_point, strerror(errno));
202 return -1;
203 }
204
205 LOGE("unknown fs_type \"%s\" for %s\n", v->fs_type, v->mount_point);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800206 return -1;
207}
208
Doug Zongkerd4208f92010-09-20 12:16:13 -0700209int ensure_path_unmounted(const char* path) {
Dees_Troyc51f1f92012-09-20 15:32:13 -0400210 if (PartitionManager.UnMount_By_Path(path, true))
211 return 0;
212 else
213 return -1;
Doug Zongkerd4208f92010-09-20 12:16:13 -0700214 Volume* v = volume_for_path(path);
215 if (v == NULL) {
216 LOGE("unknown volume for path [%s]\n", path);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800217 return -1;
218 }
Doug Zongkerc18eeb82010-09-21 16:49:26 -0700219 if (strcmp(v->fs_type, "ramdisk") == 0) {
220 // the ramdisk is always mounted; you can't unmount it.
221 return -1;
222 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800223
Doug Zongkerd4208f92010-09-20 12:16:13 -0700224 int result;
225 result = scan_mounted_volumes();
226 if (result < 0) {
227 LOGE("failed to scan mounted volumes\n");
228 return -1;
229 }
230
231 const MountedVolume* mv =
232 find_mounted_volume_by_mount_point(v->mount_point);
233 if (mv == NULL) {
234 // volume is already unmounted
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800235 return 0;
236 }
237
Doug Zongkerd4208f92010-09-20 12:16:13 -0700238 return unmount_mounted_volume(mv);
239}
240
241int format_volume(const char* volume) {
Dees_Troyc51f1f92012-09-20 15:32:13 -0400242 if (PartitionManager.Wipe_By_Path(volume))
243 return 0;
244 else
245 return -1;
Doug Zongkerd4208f92010-09-20 12:16:13 -0700246 Volume* v = volume_for_path(volume);
247 if (v == NULL) {
248 LOGE("unknown volume \"%s\"\n", volume);
249 return -1;
250 }
Doug Zongkerc18eeb82010-09-21 16:49:26 -0700251 if (strcmp(v->fs_type, "ramdisk") == 0) {
252 // you can't format the ramdisk.
253 LOGE("can't format_volume \"%s\"", volume);
254 return -1;
255 }
Doug Zongkerd4208f92010-09-20 12:16:13 -0700256 if (strcmp(v->mount_point, volume) != 0) {
257 LOGE("can't give path \"%s\" to format_volume\n", volume);
258 return -1;
259 }
260
261 if (ensure_path_unmounted(volume) != 0) {
262 LOGE("format_volume failed to unmount \"%s\"\n", v->mount_point);
263 return -1;
264 }
265
266 if (strcmp(v->fs_type, "yaffs2") == 0 || strcmp(v->fs_type, "mtd") == 0) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800267 mtd_scan_partitions();
Doug Zongkerd4208f92010-09-20 12:16:13 -0700268 const MtdPartition* partition = mtd_find_partition_by_name(v->device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800269 if (partition == NULL) {
Doug Zongkerd4208f92010-09-20 12:16:13 -0700270 LOGE("format_volume: no MTD partition \"%s\"\n", v->device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800271 return -1;
272 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800273
Doug Zongkerd4208f92010-09-20 12:16:13 -0700274 MtdWriteContext *write = mtd_write_partition(partition);
275 if (write == NULL) {
276 LOGW("format_volume: can't open MTD \"%s\"\n", v->device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800277 return -1;
Doug Zongkerd4208f92010-09-20 12:16:13 -0700278 } else if (mtd_erase_blocks(write, -1) == (off_t) -1) {
279 LOGW("format_volume: can't erase MTD \"%s\"\n", v->device);
280 mtd_write_close(write);
281 return -1;
282 } else if (mtd_write_close(write)) {
283 LOGW("format_volume: can't close MTD \"%s\"\n", v->device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800284 return -1;
285 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800286 return 0;
287 }
288
Doug Zongkerd4208f92010-09-20 12:16:13 -0700289 if (strcmp(v->fs_type, "ext4") == 0) {
Dees_Troy38bd7602012-09-14 13:33:53 -0400290#ifdef USE_EXT4
Dees_Troyab10ee22012-09-21 14:27:30 -0400291/*
Stephen Smalley779701d2012-02-09 14:13:23 -0500292 int result = make_ext4fs(v->device, v->length, volume, sehandle);
Dees_Troyab10ee22012-09-21 14:27:30 -0400293*/
294 int result = 0;
Dees_Troy38bd7602012-09-14 13:33:53 -0400295#else
296 int result = 0;
297#endif
Doug Zongkerd4208f92010-09-20 12:16:13 -0700298 if (result != 0) {
299 LOGE("format_volume: make_extf4fs failed on %s\n", v->device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800300 return -1;
301 }
Doug Zongkerd4208f92010-09-20 12:16:13 -0700302 return 0;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800303 }
Doug Zongkerd4208f92010-09-20 12:16:13 -0700304
305 LOGE("format_volume: fs_type \"%s\" unsupported\n", v->fs_type);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800306 return -1;
307}