blob: 529975a4988f7b0a18bc5c9c87676021c40b90b9 [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 Mehat586536c2010-02-16 17:12:00 -080043#include "Process.h"
San Mehatf1b736b2009-10-10 17:22:08 -070044
San Mehata2677e42009-12-13 10:40:18 -080045extern "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
San Mehat62e5dd22010-02-06 09:53:22 -0800159 LOGI("Formatting volume %s (%s)", getLabel(), devicePath);
San Mehata2677e42009-12-13 10:40:18 -0800160
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 Mehatbf041852010-01-04 10:09:16 -0800169 if (Fat::format(devicePath)) {
San Mehata2677e42009-12-13 10:40:18 -0800170 LOGE("Failed to format (%s)", strerror(errno));
171 goto err;
172 }
173
San Mehat49e2bce2009-10-12 16:29:01 -0700174 return 0;
San Mehata2677e42009-12-13 10:40:18 -0800175err:
176 return -1;
177}
178
179bool Volume::isMountpointMounted(const char *path) {
180 char device[256];
181 char mount_path[256];
182 char rest[256];
183 FILE *fp;
184 char line[1024];
185
186 if (!(fp = fopen("/proc/mounts", "r"))) {
187 LOGE("Error opening /proc/mounts (%s)", strerror(errno));
188 return false;
189 }
190
191 while(fgets(line, sizeof(line), fp)) {
192 line[strlen(line)-1] = '\0';
193 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
194 if (!strcmp(mount_path, path)) {
195 fclose(fp);
196 return true;
197 }
198
199 }
200
201 fclose(fp);
202 return false;
203}
204
205int Volume::mountVol() {
206 dev_t deviceNodes[4];
207 int n, i, rc = 0;
208 char errmsg[255];
209
210 if (getState() == Volume::State_NoMedia) {
211 snprintf(errmsg, sizeof(errmsg),
212 "Volume %s %s mount failed - no media",
213 getLabel(), getMountpoint());
214 mVm->getBroadcaster()->sendBroadcast(
215 ResponseCode::VolumeMountFailedNoMedia,
216 errmsg, false);
217 errno = ENODEV;
218 return -1;
219 } else if (getState() != Volume::State_Idle) {
220 errno = EBUSY;
221 return -1;
222 }
223
224 if (isMountpointMounted(getMountpoint())) {
225 LOGW("Volume is idle but appears to be mounted - fixing");
226 setState(Volume::State_Mounted);
227 // mCurrentlyMountedKdev = XXX
228 return 0;
229 }
230
231 n = getDeviceNodes((dev_t *) &deviceNodes, 4);
232 if (!n) {
233 LOGE("Failed to get device nodes (%s)\n", strerror(errno));
234 return -1;
235 }
236
237 for (i = 0; i < n; i++) {
238 char devicePath[255];
239
240 sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(deviceNodes[i]),
241 MINOR(deviceNodes[i]));
242
243 LOGI("%s being considered for volume %s\n", devicePath, getLabel());
244
245 errno = 0;
San Mehatbf041852010-01-04 10:09:16 -0800246 setState(Volume::State_Checking);
247
248 if ((rc = Fat::check(devicePath))) {
San Mehata2677e42009-12-13 10:40:18 -0800249 if (errno == ENODATA) {
250 LOGW("%s does not contain a FAT filesystem\n", devicePath);
251 continue;
San Mehata2677e42009-12-13 10:40:18 -0800252 }
San Mehateba65e92010-01-29 05:15:16 -0800253 errno = EIO;
254 /* Badness - abort the mount */
255 LOGE("%s failed FS checks (%s)", devicePath, strerror(errno));
256 setState(Volume::State_Idle);
257 return -1;
San Mehata2677e42009-12-13 10:40:18 -0800258 }
259
San Mehata2677e42009-12-13 10:40:18 -0800260 errno = 0;
San Mehatfff0b472010-01-06 19:19:46 -0800261 if (!(rc = Fat::doMount(devicePath, getMountpoint(), false, false,
262 1000, 1015, 0702, true))) {
San Mehateba65e92010-01-29 05:15:16 -0800263 LOGI("%s sucessfully mounted for volume %s\n", devicePath, getLabel());
San Mehata2677e42009-12-13 10:40:18 -0800264 setState(Volume::State_Mounted);
265 mCurrentlyMountedKdev = deviceNodes[i];
San Mehateba65e92010-01-29 05:15:16 -0800266 return 0;
San Mehata2677e42009-12-13 10:40:18 -0800267 }
268
269 LOGW("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno));
270 }
271
San Mehata2677e42009-12-13 10:40:18 -0800272 LOGE("Volume %s found no suitable devices for mounting :(\n", getLabel());
273 setState(Volume::State_Idle);
274
San Mehateba65e92010-01-29 05:15:16 -0800275 return -1;
San Mehata2677e42009-12-13 10:40:18 -0800276}
277
San Mehata2677e42009-12-13 10:40:18 -0800278int Volume::unmountVol() {
279 int i, rc;
280
281 if (getState() != Volume::State_Mounted) {
282 LOGE("Volume %s unmount request when not mounted", getLabel());
283 errno = EINVAL;
284 return -1;
285 }
286
287 setState(Volume::State_Unmounting);
San Mehat62e5dd22010-02-06 09:53:22 -0800288 usleep(1000 * 200); // Give the framework some time to react
San Mehat8c940ef2010-02-13 14:19:53 -0800289 for (i = 1; i <= 10; i++) {
San Mehata2677e42009-12-13 10:40:18 -0800290 rc = umount(getMountpoint());
291 if (!rc)
292 break;
293
294 if (rc && (errno == EINVAL || errno == ENOENT)) {
295 rc = 0;
296 break;
297 }
298
299 LOGW("Volume %s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -0800300 getLabel(), i, strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -0800301
San Mehat8c940ef2010-02-13 14:19:53 -0800302 int action;
303
304 if (i > 8) {
305 action = 2; // SIGKILL
306 } else if (i > 7) {
307 action = 1; // SIGHUP
308 } else
309 action = 0; // just complain
310
San Mehat586536c2010-02-16 17:12:00 -0800311 Process::killProcessesWithOpenFiles(getMountpoint(), action);
San Mehat8c940ef2010-02-13 14:19:53 -0800312 usleep(1000*250);
San Mehata2677e42009-12-13 10:40:18 -0800313 }
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}