blob: a4621966f9419058cc04dcb08be0ae73f0a1111f [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
17#include <stdio.h>
San Mehatfd7f5872009-10-12 11:32:47 -070018#include <stdlib.h>
19#include <string.h>
San Mehatf1b736b2009-10-10 17:22:08 -070020#include <errno.h>
San Mehata2677e42009-12-13 10:40:18 -080021#include <fcntl.h>
San Mehata19b2502010-01-06 10:33:53 -080022#include <sys/stat.h>
23#include <sys/types.h>
24#include <sys/mount.h>
25
San Mehata2677e42009-12-13 10:40:18 -080026#include <linux/kdev_t.h>
San Mehatf1b736b2009-10-10 17:22:08 -070027
28#define LOG_TAG "Vold"
29
30#include <cutils/log.h>
31
San Mehatfd7f5872009-10-12 11:32:47 -070032#include <sysutils/NetlinkEvent.h>
33
San Mehatf1b736b2009-10-10 17:22:08 -070034#include "VolumeManager.h"
San Mehatae10b912009-10-12 14:57:05 -070035#include "DirectVolume.h"
San Mehata2677e42009-12-13 10:40:18 -080036#include "ResponseCode.h"
San Mehata19b2502010-01-06 10:33:53 -080037#include "Loop.h"
38#include "Fat.h"
San Mehatf1b736b2009-10-10 17:22:08 -070039
San Mehat23969932010-01-09 07:08:06 -080040extern "C" void KillProcessesWithOpenFiles(const char *, int, int, int);
41
San Mehatf1b736b2009-10-10 17:22:08 -070042VolumeManager *VolumeManager::sInstance = NULL;
43
44VolumeManager *VolumeManager::Instance() {
45 if (!sInstance)
46 sInstance = new VolumeManager();
47 return sInstance;
48}
49
50VolumeManager::VolumeManager() {
51 mBlockDevices = new BlockDeviceCollection();
52 mVolumes = new VolumeCollection();
53 mBroadcaster = NULL;
San Mehata2677e42009-12-13 10:40:18 -080054 mUsbMassStorageConnected = false;
San Mehatf1b736b2009-10-10 17:22:08 -070055}
56
57VolumeManager::~VolumeManager() {
58 delete mBlockDevices;
59}
60
61int VolumeManager::start() {
62 return 0;
63}
64
65int VolumeManager::stop() {
66 return 0;
67}
68
69int VolumeManager::addVolume(Volume *v) {
70 mVolumes->push_back(v);
71 return 0;
72}
73
San Mehata2677e42009-12-13 10:40:18 -080074void VolumeManager::notifyUmsConnected(bool connected) {
75 char msg[255];
76
77 if (connected) {
78 mUsbMassStorageConnected = true;
79 } else {
80 mUsbMassStorageConnected = false;
81 }
82 snprintf(msg, sizeof(msg), "Share method ums now %s",
83 (connected ? "available" : "unavailable"));
84
85 getBroadcaster()->sendBroadcast(ResponseCode::ShareAvailabilityChange,
86 msg, false);
87}
88
89void VolumeManager::handleSwitchEvent(NetlinkEvent *evt) {
San Mehat0cde53c2009-12-22 08:32:33 -080090 const char *devpath = evt->findParam("DEVPATH");
San Mehata2677e42009-12-13 10:40:18 -080091 const char *name = evt->findParam("SWITCH_NAME");
92 const char *state = evt->findParam("SWITCH_STATE");
93
San Mehat0cde53c2009-12-22 08:32:33 -080094 if (!name || !state) {
95 LOGW("Switch %s event missing name/state info", devpath);
96 return;
97 }
98
San Mehata2677e42009-12-13 10:40:18 -080099 if (!strcmp(name, "usb_mass_storage")) {
100
101 if (!strcmp(state, "online")) {
102 notifyUmsConnected(true);
103 } else {
104 notifyUmsConnected(false);
105 }
106 } else {
107 LOGW("Ignoring unknown switch '%s'", name);
108 }
109}
110
San Mehatfd7f5872009-10-12 11:32:47 -0700111void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
112 const char *devpath = evt->findParam("DEVPATH");
San Mehatf1b736b2009-10-10 17:22:08 -0700113
San Mehatfd7f5872009-10-12 11:32:47 -0700114 /* Lookup a volume to handle this device */
San Mehatf1b736b2009-10-10 17:22:08 -0700115 VolumeCollection::iterator it;
116 bool hit = false;
117 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
San Mehatfd7f5872009-10-12 11:32:47 -0700118 if (!(*it)->handleBlockEvent(evt)) {
San Mehata2677e42009-12-13 10:40:18 -0800119#ifdef NETLINK_DEBUG
120 LOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
121#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700122 hit = true;
San Mehatf1b736b2009-10-10 17:22:08 -0700123 break;
124 }
125 }
126
127 if (!hit) {
San Mehata2677e42009-12-13 10:40:18 -0800128#ifdef NETLINK_DEBUG
San Mehatfd7f5872009-10-12 11:32:47 -0700129 LOGW("No volumes handled block event for '%s'", devpath);
San Mehata2677e42009-12-13 10:40:18 -0800130#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700131 }
132}
133
San Mehatf1b736b2009-10-10 17:22:08 -0700134int VolumeManager::listVolumes(SocketClient *cli) {
135 VolumeCollection::iterator i;
136
137 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
138 char *buffer;
139 asprintf(&buffer, "%s %s %d",
140 (*i)->getLabel(), (*i)->getMountpoint(),
141 (*i)->getState());
San Mehata2677e42009-12-13 10:40:18 -0800142 cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
San Mehatf1b736b2009-10-10 17:22:08 -0700143 free(buffer);
144 }
San Mehata2677e42009-12-13 10:40:18 -0800145 cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
San Mehatf1b736b2009-10-10 17:22:08 -0700146 return 0;
147}
San Mehat49e2bce2009-10-12 16:29:01 -0700148
San Mehata2677e42009-12-13 10:40:18 -0800149int VolumeManager::formatVolume(const char *label) {
150 Volume *v = lookupVolume(label);
151
152 if (!v) {
153 errno = ENOENT;
154 return -1;
155 }
156
157 return v->formatVol();
158}
159
San Mehata19b2502010-01-06 10:33:53 -0800160int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
161 char mountPoint[255];
162
163 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
164
165 if (!isMountpointMounted(mountPoint)) {
166 errno = ENOENT;
167 return -1;
168 }
169 snprintf(buffer, maxlen, "/asec/%s", id);
170 return 0;
171}
172
173int VolumeManager::createAsec(const char *id, int sizeMb,
174 const char *fstype, const char *key, int ownerUid) {
175
176 mkdir("/sdcard/android_secure", 0777);
177
178 if (lookupVolume(id)) {
179 LOGE("ASEC volume '%s' currently exists", id);
180 errno = EADDRINUSE;
181 return -1;
182 }
183
184 char asecFileName[255];
185 snprintf(asecFileName, sizeof(asecFileName),
186 "/sdcard/android_secure/%s.asec", id);
187
188 if (!access(asecFileName, F_OK)) {
189 LOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
190 asecFileName, strerror(errno));
191 errno = EADDRINUSE;
192 return -1;
193 }
194
195 if (Loop::createImageFile(asecFileName, sizeMb)) {
196 LOGE("ASEC image file creation failed (%s)", strerror(errno));
197 return -1;
198 }
199
200 char loopDevice[255];
San Mehat8da6bcb2010-01-09 12:24:05 -0800201 if (Loop::create(asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800202 LOGE("ASEC loop device creation failed (%s)", strerror(errno));
203 unlink(asecFileName);
204 return -1;
205 }
206
207 /* XXX: Start devmapper */
208
209 if (Fat::format(loopDevice)) {
210 LOGE("ASEC FAT format failed (%s)", strerror(errno));
211 Loop::destroyByDevice(loopDevice);
212 unlink(asecFileName);
213 return -1;
214 }
215
216 char mountPoint[255];
217
218 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
219 if (mkdir(mountPoint, 0777)) {
San Mehateb13a902010-01-07 12:12:50 -0800220 if (errno != EEXIST) {
221 LOGE("Mountpoint creation failed (%s)", strerror(errno));
222 Loop::destroyByDevice(loopDevice);
223 unlink(asecFileName);
224 return -1;
225 }
San Mehata19b2502010-01-06 10:33:53 -0800226 }
227
San Mehatfff0b472010-01-06 19:19:46 -0800228 if (Fat::doMount(loopDevice, mountPoint, false, false, ownerUid,
San Mehatcff5ec32010-01-08 12:31:44 -0800229 0, 0000, false)) {
230// 0, 0007, false)) {
San Mehata19b2502010-01-06 10:33:53 -0800231 LOGE("ASEC FAT mount failed (%s)", strerror(errno));
232 Loop::destroyByDevice(loopDevice);
233 unlink(asecFileName);
234 return -1;
235 }
236
237 return 0;
238}
239
240int VolumeManager::finalizeAsec(const char *id) {
241 char asecFileName[255];
242 char loopDevice[255];
243 char mountPoint[255];
244
245 snprintf(asecFileName, sizeof(asecFileName),
246 "/sdcard/android_secure/%s.asec", id);
247
248 if (Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
249 LOGE("Unable to finalize %s (%s)", id, strerror(errno));
250 return -1;
251 }
252
253 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
San Mehatfff0b472010-01-06 19:19:46 -0800254 // XXX:
255 if (Fat::doMount(loopDevice, mountPoint, true, true, 0, 0, 0227, false)) {
San Mehata19b2502010-01-06 10:33:53 -0800256 LOGE("ASEC finalize mount failed (%s)", strerror(errno));
257 return -1;
258 }
259
260 LOGD("ASEC %s finalized", id);
261 return 0;
262}
263
264int VolumeManager::destroyAsec(const char *id) {
265 char asecFileName[255];
266 char mountPoint[255];
267
268 snprintf(asecFileName, sizeof(asecFileName),
269 "/sdcard/android_secure/%s.asec", id);
270 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
271
272 if (isMountpointMounted(mountPoint)) {
273 int i, rc;
274 for (i = 0; i < 10; i++) {
275 rc = umount(mountPoint);
276 if (!rc) {
277 break;
278 }
279 if (rc && (errno == EINVAL || errno == ENOENT)) {
280 rc = 0;
281 break;
282 }
283 LOGW("ASEC %s unmount attempt %d failed (%s)",
284 id, i +1, strerror(errno));
San Mehat23969932010-01-09 07:08:06 -0800285
286 if (i >= 5) {
287 KillProcessesWithOpenFiles(mountPoint, (i < 7 ? 0 : 1),
288 NULL, 0);
289 }
San Mehata19b2502010-01-06 10:33:53 -0800290 usleep(1000 * 250);
291 }
292 if (rc) {
293 LOGE("Failed to unmount ASEC %s for destroy", id);
294 return -1;
295 }
296 }
297
298 char loopDevice[255];
299 if (!Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
300 Loop::destroyByDevice(loopDevice);
301 }
302
303 unlink(asecFileName);
304
305 LOGD("ASEC %s destroyed", id);
306 return 0;
307}
308
309int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
310 char asecFileName[255];
311 char mountPoint[255];
312
313 snprintf(asecFileName, sizeof(asecFileName),
314 "/sdcard/android_secure/%s.asec", id);
315 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
316
317 if (isMountpointMounted(mountPoint)) {
318 LOGE("ASEC %s already mounted", id);
319 errno = EBUSY;
320 return -1;
321 }
322
323 char loopDevice[255];
324 if (Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat8da6bcb2010-01-09 12:24:05 -0800325 if (Loop::create(asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800326 LOGE("ASEC loop device creation failed (%s)", strerror(errno));
327 return -1;
328 }
329 }
330
331 if (mkdir(mountPoint, 0777)) {
332 LOGE("Mountpoint creation failed (%s)", strerror(errno));
333 return -1;
334 }
335
San Mehatfff0b472010-01-06 19:19:46 -0800336 if (Fat::doMount(loopDevice, mountPoint, true, false, ownerUid, 0,
San Mehatcff5ec32010-01-08 12:31:44 -0800337 0222, false)) {
338// 0227, false)) {
San Mehata19b2502010-01-06 10:33:53 -0800339 LOGE("ASEC mount failed (%s)", strerror(errno));
340 return -1;
341 }
342
343 LOGD("ASEC %s mounted", id);
344 return 0;
345}
346
San Mehat49e2bce2009-10-12 16:29:01 -0700347int VolumeManager::mountVolume(const char *label) {
348 Volume *v = lookupVolume(label);
349
350 if (!v) {
351 errno = ENOENT;
352 return -1;
353 }
354
San Mehata2677e42009-12-13 10:40:18 -0800355 return v->mountVol();
356}
357
358int VolumeManager::shareAvailable(const char *method, bool *avail) {
359
360 if (strcmp(method, "ums")) {
361 errno = ENOSYS;
362 return -1;
363 }
364
365 if (mUsbMassStorageConnected)
366 *avail = true;
367 else
368 *avail = false;
369 return 0;
370}
371
372int VolumeManager::simulate(const char *cmd, const char *arg) {
373
374 if (!strcmp(cmd, "ums")) {
375 if (!strcmp(arg, "connect")) {
376 notifyUmsConnected(true);
377 } else if (!strcmp(arg, "disconnect")) {
378 notifyUmsConnected(false);
379 } else {
380 errno = EINVAL;
381 return -1;
382 }
383 } else {
384 errno = EINVAL;
385 return -1;
386 }
387 return 0;
388}
389
390int VolumeManager::shareVolume(const char *label, const char *method) {
391 Volume *v = lookupVolume(label);
392
393 if (!v) {
394 errno = ENOENT;
395 return -1;
396 }
397
398 /*
399 * Eventually, we'll want to support additional share back-ends,
400 * some of which may work while the media is mounted. For now,
401 * we just support UMS
402 */
403 if (strcmp(method, "ums")) {
404 errno = ENOSYS;
405 return -1;
406 }
407
408 if (v->getState() == Volume::State_NoMedia) {
409 errno = ENODEV;
410 return -1;
411 }
412
San Mehat49e2bce2009-10-12 16:29:01 -0700413 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -0800414 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -0700415 errno = EBUSY;
416 return -1;
417 }
418
San Mehata2677e42009-12-13 10:40:18 -0800419 dev_t d = v->getDiskDevice();
420 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
421 // This volume does not support raw disk access
422 errno = EINVAL;
423 return -1;
424 }
425
426 int fd;
427 char nodepath[255];
428 snprintf(nodepath,
429 sizeof(nodepath), "/dev/block/vold/%d:%d",
430 MAJOR(d), MINOR(d));
431
San Mehat0cde53c2009-12-22 08:32:33 -0800432 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file",
433 O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800434 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
435 return -1;
436 }
437
438 if (write(fd, nodepath, strlen(nodepath)) < 0) {
439 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
440 close(fd);
441 return -1;
442 }
443
444 close(fd);
445 v->handleVolumeShared();
446 return 0;
447}
448
449int VolumeManager::unshareVolume(const char *label, const char *method) {
450 Volume *v = lookupVolume(label);
451
452 if (!v) {
453 errno = ENOENT;
454 return -1;
455 }
456
457 if (strcmp(method, "ums")) {
458 errno = ENOSYS;
459 return -1;
460 }
461
462 if (v->getState() != Volume::State_Shared) {
463 errno = EINVAL;
464 return -1;
465 }
466
467 dev_t d = v->getDiskDevice();
468
469 int fd;
470 char nodepath[255];
471 snprintf(nodepath,
472 sizeof(nodepath), "/dev/block/vold/%d:%d",
473 MAJOR(d), MINOR(d));
474
San Mehat0cde53c2009-12-22 08:32:33 -0800475 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file", O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800476 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
477 return -1;
478 }
479
480 char ch = 0;
481 if (write(fd, &ch, 1) < 0) {
482 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
483 close(fd);
484 return -1;
485 }
486
487 close(fd);
488 v->handleVolumeUnshared();
489 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -0700490}
491
492int VolumeManager::unmountVolume(const char *label) {
493 Volume *v = lookupVolume(label);
494
495 if (!v) {
496 errno = ENOENT;
497 return -1;
498 }
499
San Mehata2677e42009-12-13 10:40:18 -0800500 if (v->getState() == Volume::State_NoMedia) {
501 errno = ENODEV;
502 return -1;
503 }
504
San Mehat49e2bce2009-10-12 16:29:01 -0700505 if (v->getState() != Volume::State_Mounted) {
San Mehata2677e42009-12-13 10:40:18 -0800506 LOGW("Attempt to unmount volume which isn't mounted (%d)\n",
507 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -0700508 errno = EBUSY;
509 return -1;
510 }
511
San Mehata2677e42009-12-13 10:40:18 -0800512 return v->unmountVol();
San Mehat49e2bce2009-10-12 16:29:01 -0700513}
514
San Mehata2677e42009-12-13 10:40:18 -0800515/*
516 * Looks up a volume by it's label or mount-point
517 */
San Mehat49e2bce2009-10-12 16:29:01 -0700518Volume *VolumeManager::lookupVolume(const char *label) {
519 VolumeCollection::iterator i;
520
521 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -0800522 if (label[0] == '/') {
523 if (!strcmp(label, (*i)->getMountpoint()))
524 return (*i);
525 } else {
526 if (!strcmp(label, (*i)->getLabel()))
527 return (*i);
528 }
San Mehat49e2bce2009-10-12 16:29:01 -0700529 }
530 return NULL;
531}
San Mehata19b2502010-01-06 10:33:53 -0800532
533bool VolumeManager::isMountpointMounted(const char *mp)
534{
535 char device[256];
536 char mount_path[256];
537 char rest[256];
538 FILE *fp;
539 char line[1024];
540
541 if (!(fp = fopen("/proc/mounts", "r"))) {
542 LOGE("Error opening /proc/mounts (%s)", strerror(errno));
543 return false;
544 }
545
546 while(fgets(line, sizeof(line), fp)) {
547 line[strlen(line)-1] = '\0';
548 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
549 if (!strcmp(mount_path, mp)) {
550 fclose(fp);
551 return true;
552 }
553
554 }
555
556 fclose(fp);
557 return false;
558}
559