blob: f1a9203dd0dc0920718177dad8c986ca91b98dfb [file] [log] [blame]
San Mehatf1b736b2009-10-10 17:22:08 -07001/*
2 * Copyright (C) 2008 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
San Mehat49e2bce2009-10-12 16:29:01 -070017#include <stdlib.h>
San Mehatf1b736b2009-10-10 17:22:08 -070018#include <string.h>
San Mehat49e2bce2009-10-12 16:29:01 -070019#include <dirent.h>
20#include <errno.h>
21#include <fcntl.h>
22
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26#include <sys/mman.h>
San Mehata2677e42009-12-13 10:40:18 -080027#include <sys/mount.h>
28
29#include <linux/kdev_t.h>
30
31#include <cutils/properties.h>
32
33#include "diskmbr.h"
San Mehatf1b736b2009-10-10 17:22:08 -070034
35#define LOG_TAG "Vold"
36
37#include <cutils/log.h>
38
39#include "Volume.h"
San Mehata2677e42009-12-13 10:40:18 -080040#include "VolumeManager.h"
41#include "ResponseCode.h"
San Mehatbf041852010-01-04 10:09:16 -080042#include "Fat.h"
San Mehatf1b736b2009-10-10 17:22:08 -070043
San Mehata2677e42009-12-13 10:40:18 -080044extern "C" void KillProcessesWithOpenFiles(const char *, int, int, int);
45extern "C" void dos_partition_dec(void const *pp, struct dos_partition *d);
46extern "C" void dos_partition_enc(void *pp, struct dos_partition *d);
San Mehat49e2bce2009-10-12 16:29:01 -070047
San Mehata2677e42009-12-13 10:40:18 -080048static const char *stateToStr(int state) {
49 if (state == Volume::State_Init)
50 return "Initializing";
51 else if (state == Volume::State_NoMedia)
52 return "No-Media";
53 else if (state == Volume::State_Idle)
54 return "Idle-Unmounted";
55 else if (state == Volume::State_Pending)
56 return "Pending";
57 else if (state == Volume::State_Mounted)
58 return "Mounted";
59 else if (state == Volume::State_Unmounting)
60 return "Unmounting";
61 else if (state == Volume::State_Checking)
62 return "Checking";
63 else if (state == Volume::State_Formatting)
64 return "Formatting";
65 else if (state == Volume::State_Shared)
66 return "Shared-Unmounted";
67 else if (state == Volume::State_SharedMnt)
68 return "Shared-Mounted";
69 else
70 return "Unknown-Error";
71}
72
73Volume::Volume(VolumeManager *vm, const char *label, const char *mount_point) {
74 mVm = vm;
San Mehatf1b736b2009-10-10 17:22:08 -070075 mLabel = strdup(label);
76 mMountpoint = strdup(mount_point);
77 mState = Volume::State_Init;
San Mehata2677e42009-12-13 10:40:18 -080078 mCurrentlyMountedKdev = -1;
San Mehatf1b736b2009-10-10 17:22:08 -070079}
80
81Volume::~Volume() {
82 free(mLabel);
83 free(mMountpoint);
84}
85
San Mehata2677e42009-12-13 10:40:18 -080086dev_t Volume::getDiskDevice() {
87 return MKDEV(0, 0);
88};
89
90void Volume::handleVolumeShared() {
91}
92
93void Volume::handleVolumeUnshared() {
94}
95
San Mehatfd7f5872009-10-12 11:32:47 -070096int Volume::handleBlockEvent(NetlinkEvent *evt) {
San Mehatf1b736b2009-10-10 17:22:08 -070097 errno = ENOSYS;
98 return -1;
99}
100
101void Volume::setState(int state) {
San Mehata2677e42009-12-13 10:40:18 -0800102 char msg[255];
103 int oldState = mState;
104
105 if (oldState == state) {
106 LOGW("Duplicate state (%d)\n", state);
107 return;
108 }
109
San Mehatf1b736b2009-10-10 17:22:08 -0700110 mState = state;
San Mehata2677e42009-12-13 10:40:18 -0800111
112 LOGD("Volume %s state changing %d (%s) -> %d (%s)", mLabel,
113 oldState, stateToStr(oldState), mState, stateToStr(mState));
114 snprintf(msg, sizeof(msg),
115 "Volume %s %s state changed from %d (%s) to %d (%s)", getLabel(),
116 getMountpoint(), oldState, stateToStr(oldState), mState,
117 stateToStr(mState));
118
119 mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeStateChange,
120 msg, false);
San Mehatf1b736b2009-10-10 17:22:08 -0700121}
San Mehat49e2bce2009-10-12 16:29:01 -0700122
San Mehatdd9b8e92009-10-21 11:06:52 -0700123int Volume::createDeviceNode(const char *path, int major, int minor) {
124 mode_t mode = 0660 | S_IFBLK;
125 dev_t dev = (major << 8) | minor;
126 if (mknod(path, mode, dev) < 0) {
127 if (errno != EEXIST) {
128 return -1;
129 }
130 }
131 return 0;
132}
133
San Mehata2677e42009-12-13 10:40:18 -0800134int Volume::formatVol() {
San Mehat49e2bce2009-10-12 16:29:01 -0700135
San Mehata2677e42009-12-13 10:40:18 -0800136 if (getState() == Volume::State_NoMedia) {
137 errno = ENODEV;
138 return -1;
139 } else if (getState() != Volume::State_Idle) {
140 errno = EBUSY;
San Mehat49e2bce2009-10-12 16:29:01 -0700141 return -1;
142 }
143
San Mehata2677e42009-12-13 10:40:18 -0800144 if (isMountpointMounted(getMountpoint())) {
145 LOGW("Volume is idle but appears to be mounted - fixing");
146 setState(Volume::State_Mounted);
147 // mCurrentlyMountedKdev = XXX
148 errno = EBUSY;
San Mehat49e2bce2009-10-12 16:29:01 -0700149 return -1;
150 }
151
San Mehata2677e42009-12-13 10:40:18 -0800152 char devicePath[255];
153 dev_t diskNode = getDiskDevice();
154 dev_t partNode = MKDEV(MAJOR(diskNode), 1); // XXX: Hmmm
155
156 sprintf(devicePath, "/dev/block/vold/%d:%d",
157 MAJOR(diskNode), MINOR(diskNode));
158
159 LOGI("Volume %s (%s) MBR being initialized", getLabel(), devicePath);
160
161 if (initializeMbr(devicePath)) {
162 LOGE("Failed to initialize MBR (%s)", strerror(errno));
163 goto err;
San Mehat49e2bce2009-10-12 16:29:01 -0700164 }
165
San Mehata2677e42009-12-13 10:40:18 -0800166 sprintf(devicePath, "/dev/block/vold/%d:%d",
167 MAJOR(partNode), MINOR(partNode));
San Mehatdd9b8e92009-10-21 11:06:52 -0700168
San Mehata2677e42009-12-13 10:40:18 -0800169 LOGI("Volume %s (%s) being formatted", getLabel(), devicePath);
170
San Mehatbf041852010-01-04 10:09:16 -0800171 if (Fat::format(devicePath)) {
San Mehata2677e42009-12-13 10:40:18 -0800172 LOGE("Failed to format (%s)", strerror(errno));
173 goto err;
174 }
175
176 LOGI("Volume %s (%s) formatted sucessfully", getLabel(), devicePath);
San Mehat49e2bce2009-10-12 16:29:01 -0700177 return 0;
San Mehata2677e42009-12-13 10:40:18 -0800178err:
179 return -1;
180}
181
182bool Volume::isMountpointMounted(const char *path) {
183 char device[256];
184 char mount_path[256];
185 char rest[256];
186 FILE *fp;
187 char line[1024];
188
189 if (!(fp = fopen("/proc/mounts", "r"))) {
190 LOGE("Error opening /proc/mounts (%s)", strerror(errno));
191 return false;
192 }
193
194 while(fgets(line, sizeof(line), fp)) {
195 line[strlen(line)-1] = '\0';
196 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
197 if (!strcmp(mount_path, path)) {
198 fclose(fp);
199 return true;
200 }
201
202 }
203
204 fclose(fp);
205 return false;
206}
207
208int Volume::mountVol() {
209 dev_t deviceNodes[4];
210 int n, i, rc = 0;
211 char errmsg[255];
212
213 if (getState() == Volume::State_NoMedia) {
214 snprintf(errmsg, sizeof(errmsg),
215 "Volume %s %s mount failed - no media",
216 getLabel(), getMountpoint());
217 mVm->getBroadcaster()->sendBroadcast(
218 ResponseCode::VolumeMountFailedNoMedia,
219 errmsg, false);
220 errno = ENODEV;
221 return -1;
222 } else if (getState() != Volume::State_Idle) {
223 errno = EBUSY;
224 return -1;
225 }
226
227 if (isMountpointMounted(getMountpoint())) {
228 LOGW("Volume is idle but appears to be mounted - fixing");
229 setState(Volume::State_Mounted);
230 // mCurrentlyMountedKdev = XXX
231 return 0;
232 }
233
234 n = getDeviceNodes((dev_t *) &deviceNodes, 4);
235 if (!n) {
236 LOGE("Failed to get device nodes (%s)\n", strerror(errno));
237 return -1;
238 }
239
240 for (i = 0; i < n; i++) {
241 char devicePath[255];
242
243 sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(deviceNodes[i]),
244 MINOR(deviceNodes[i]));
245
246 LOGI("%s being considered for volume %s\n", devicePath, getLabel());
247
248 errno = 0;
San Mehatbf041852010-01-04 10:09:16 -0800249 setState(Volume::State_Checking);
250
251 if ((rc = Fat::check(devicePath))) {
San Mehata2677e42009-12-13 10:40:18 -0800252 if (errno == ENODATA) {
253 LOGW("%s does not contain a FAT filesystem\n", devicePath);
254 continue;
San Mehata2677e42009-12-13 10:40:18 -0800255 }
San Mehateba65e92010-01-29 05:15:16 -0800256 errno = EIO;
257 /* Badness - abort the mount */
258 LOGE("%s failed FS checks (%s)", devicePath, strerror(errno));
259 setState(Volume::State_Idle);
260 return -1;
San Mehata2677e42009-12-13 10:40:18 -0800261 }
262
263 LOGI("%s checks out - attempting to mount\n", devicePath);
264 errno = 0;
San Mehatfff0b472010-01-06 19:19:46 -0800265 if (!(rc = Fat::doMount(devicePath, getMountpoint(), false, false,
266 1000, 1015, 0702, true))) {
San Mehateba65e92010-01-29 05:15:16 -0800267 LOGI("%s sucessfully mounted for volume %s\n", devicePath, getLabel());
San Mehata2677e42009-12-13 10:40:18 -0800268 setState(Volume::State_Mounted);
269 mCurrentlyMountedKdev = deviceNodes[i];
San Mehateba65e92010-01-29 05:15:16 -0800270 return 0;
San Mehata2677e42009-12-13 10:40:18 -0800271 }
272
273 LOGW("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno));
274 }
275
San Mehata2677e42009-12-13 10:40:18 -0800276 LOGE("Volume %s found no suitable devices for mounting :(\n", getLabel());
277 setState(Volume::State_Idle);
278
San Mehateba65e92010-01-29 05:15:16 -0800279 return -1;
San Mehata2677e42009-12-13 10:40:18 -0800280}
281
San Mehata2677e42009-12-13 10:40:18 -0800282int Volume::unmountVol() {
283 int i, rc;
284
285 if (getState() != Volume::State_Mounted) {
286 LOGE("Volume %s unmount request when not mounted", getLabel());
287 errno = EINVAL;
288 return -1;
289 }
290
291 setState(Volume::State_Unmounting);
292 for (i = 0; i < 10; i++) {
293 rc = umount(getMountpoint());
294 if (!rc)
295 break;
296
297 if (rc && (errno == EINVAL || errno == ENOENT)) {
298 rc = 0;
299 break;
300 }
301
302 LOGW("Volume %s unmount attempt %d failed (%s)",
303 getLabel(), i + 1, strerror(errno));
304
305 if (i < 5) {
306 usleep(1000 * 250);
307 } else {
308 KillProcessesWithOpenFiles(getMountpoint(),
309 (i < 7 ? 0 : 1),
310 NULL, 0);
311 usleep(1000 * 250);
312 }
313 }
314
315 if (!rc) {
316 LOGI("Volume %s unmounted sucessfully", getLabel());
317 setState(Volume::State_Idle);
318 mCurrentlyMountedKdev = -1;
319 return 0;
320 }
321
322 LOGE("Volume %s failed to unmount (%s)\n", getLabel(), strerror(errno));
323 setState(Volume::State_Mounted);
324 return -1;
325}
326
327int Volume::initializeMbr(const char *deviceNode) {
328 int fd, rc;
329 unsigned char block[512];
330 struct dos_partition part;
331 unsigned int nr_sec;
332
333 if ((fd = open(deviceNode, O_RDWR)) < 0) {
334 LOGE("Error opening disk file (%s)", strerror(errno));
335 return -1;
336 }
337
338 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
339 LOGE("Unable to get device size (%s)", strerror(errno));
340 close(fd);
341 return -1;
342 }
343
344 memset(&part, 0, sizeof(part));
345 part.dp_flag = 0x80;
346 part.dp_typ = 0xc;
347 part.dp_start = ((1024 * 64) / 512) + 1;
348 part.dp_size = nr_sec - part.dp_start;
349
350 memset(block, 0, sizeof(block));
351 block[0x1fe] = 0x55;
352 block[0x1ff] = 0xaa;
353
354 dos_partition_enc(block + DOSPARTOFF, &part);
355
356 if (write(fd, block, sizeof(block)) < 0) {
357 LOGE("Error writing MBR (%s)", strerror(errno));
358 close(fd);
359 return -1;
360 }
361
362 if (ioctl(fd, BLKRRPART, NULL) < 0) {
363 LOGE("Error re-reading partition table (%s)", strerror(errno));
364 close(fd);
365 return -1;
366 }
367 close(fd);
368 return 0;
369}