blob: d9c354dceae4cdabf189b2cf7e910aab7d53bee0 [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
40VolumeManager *VolumeManager::sInstance = NULL;
41
42VolumeManager *VolumeManager::Instance() {
43 if (!sInstance)
44 sInstance = new VolumeManager();
45 return sInstance;
46}
47
48VolumeManager::VolumeManager() {
49 mBlockDevices = new BlockDeviceCollection();
50 mVolumes = new VolumeCollection();
51 mBroadcaster = NULL;
San Mehata2677e42009-12-13 10:40:18 -080052 mUsbMassStorageConnected = false;
San Mehatf1b736b2009-10-10 17:22:08 -070053}
54
55VolumeManager::~VolumeManager() {
56 delete mBlockDevices;
57}
58
59int VolumeManager::start() {
60 return 0;
61}
62
63int VolumeManager::stop() {
64 return 0;
65}
66
67int VolumeManager::addVolume(Volume *v) {
68 mVolumes->push_back(v);
69 return 0;
70}
71
San Mehata2677e42009-12-13 10:40:18 -080072void VolumeManager::notifyUmsConnected(bool connected) {
73 char msg[255];
74
75 if (connected) {
76 mUsbMassStorageConnected = true;
77 } else {
78 mUsbMassStorageConnected = false;
79 }
80 snprintf(msg, sizeof(msg), "Share method ums now %s",
81 (connected ? "available" : "unavailable"));
82
83 getBroadcaster()->sendBroadcast(ResponseCode::ShareAvailabilityChange,
84 msg, false);
85}
86
87void VolumeManager::handleSwitchEvent(NetlinkEvent *evt) {
San Mehat0cde53c2009-12-22 08:32:33 -080088 const char *devpath = evt->findParam("DEVPATH");
San Mehata2677e42009-12-13 10:40:18 -080089 const char *name = evt->findParam("SWITCH_NAME");
90 const char *state = evt->findParam("SWITCH_STATE");
91
San Mehat0cde53c2009-12-22 08:32:33 -080092 if (!name || !state) {
93 LOGW("Switch %s event missing name/state info", devpath);
94 return;
95 }
96
San Mehata2677e42009-12-13 10:40:18 -080097 if (!strcmp(name, "usb_mass_storage")) {
98
99 if (!strcmp(state, "online")) {
100 notifyUmsConnected(true);
101 } else {
102 notifyUmsConnected(false);
103 }
104 } else {
105 LOGW("Ignoring unknown switch '%s'", name);
106 }
107}
108
San Mehatfd7f5872009-10-12 11:32:47 -0700109void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
110 const char *devpath = evt->findParam("DEVPATH");
San Mehatf1b736b2009-10-10 17:22:08 -0700111
San Mehatfd7f5872009-10-12 11:32:47 -0700112 /* Lookup a volume to handle this device */
San Mehatf1b736b2009-10-10 17:22:08 -0700113 VolumeCollection::iterator it;
114 bool hit = false;
115 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
San Mehatfd7f5872009-10-12 11:32:47 -0700116 if (!(*it)->handleBlockEvent(evt)) {
San Mehata2677e42009-12-13 10:40:18 -0800117#ifdef NETLINK_DEBUG
118 LOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
119#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700120 hit = true;
San Mehatf1b736b2009-10-10 17:22:08 -0700121 break;
122 }
123 }
124
125 if (!hit) {
San Mehata2677e42009-12-13 10:40:18 -0800126#ifdef NETLINK_DEBUG
San Mehatfd7f5872009-10-12 11:32:47 -0700127 LOGW("No volumes handled block event for '%s'", devpath);
San Mehata2677e42009-12-13 10:40:18 -0800128#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700129 }
130}
131
San Mehatf1b736b2009-10-10 17:22:08 -0700132int VolumeManager::listVolumes(SocketClient *cli) {
133 VolumeCollection::iterator i;
134
135 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
136 char *buffer;
137 asprintf(&buffer, "%s %s %d",
138 (*i)->getLabel(), (*i)->getMountpoint(),
139 (*i)->getState());
San Mehata2677e42009-12-13 10:40:18 -0800140 cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
San Mehatf1b736b2009-10-10 17:22:08 -0700141 free(buffer);
142 }
San Mehata2677e42009-12-13 10:40:18 -0800143 cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
San Mehatf1b736b2009-10-10 17:22:08 -0700144 return 0;
145}
San Mehat49e2bce2009-10-12 16:29:01 -0700146
San Mehata2677e42009-12-13 10:40:18 -0800147int VolumeManager::formatVolume(const char *label) {
148 Volume *v = lookupVolume(label);
149
150 if (!v) {
151 errno = ENOENT;
152 return -1;
153 }
154
155 return v->formatVol();
156}
157
San Mehata19b2502010-01-06 10:33:53 -0800158int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
159 char mountPoint[255];
160
161 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
162
163 if (!isMountpointMounted(mountPoint)) {
164 errno = ENOENT;
165 return -1;
166 }
167 snprintf(buffer, maxlen, "/asec/%s", id);
168 return 0;
169}
170
171int VolumeManager::createAsec(const char *id, int sizeMb,
172 const char *fstype, const char *key, int ownerUid) {
173
174 mkdir("/sdcard/android_secure", 0777);
175
176 if (lookupVolume(id)) {
177 LOGE("ASEC volume '%s' currently exists", id);
178 errno = EADDRINUSE;
179 return -1;
180 }
181
182 char asecFileName[255];
183 snprintf(asecFileName, sizeof(asecFileName),
184 "/sdcard/android_secure/%s.asec", id);
185
186 if (!access(asecFileName, F_OK)) {
187 LOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
188 asecFileName, strerror(errno));
189 errno = EADDRINUSE;
190 return -1;
191 }
192
193 if (Loop::createImageFile(asecFileName, sizeMb)) {
194 LOGE("ASEC image file creation failed (%s)", strerror(errno));
195 return -1;
196 }
197
198 char loopDevice[255];
199 if (Loop::getNextAvailable(loopDevice, sizeof(loopDevice))) {
200 unlink(asecFileName);
201 return -1;
202 }
203
204 if (Loop::create(loopDevice, asecFileName)) {
205 LOGE("ASEC loop device creation failed (%s)", strerror(errno));
206 unlink(asecFileName);
207 return -1;
208 }
209
210 /* XXX: Start devmapper */
211
212 if (Fat::format(loopDevice)) {
213 LOGE("ASEC FAT format failed (%s)", strerror(errno));
214 Loop::destroyByDevice(loopDevice);
215 unlink(asecFileName);
216 return -1;
217 }
218
219 char mountPoint[255];
220
221 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
222 if (mkdir(mountPoint, 0777)) {
San Mehateb13a902010-01-07 12:12:50 -0800223 if (errno != EEXIST) {
224 LOGE("Mountpoint creation failed (%s)", strerror(errno));
225 Loop::destroyByDevice(loopDevice);
226 unlink(asecFileName);
227 return -1;
228 }
San Mehata19b2502010-01-06 10:33:53 -0800229 }
230
San Mehatfff0b472010-01-06 19:19:46 -0800231 if (Fat::doMount(loopDevice, mountPoint, false, false, ownerUid,
San Mehatcff5ec32010-01-08 12:31:44 -0800232 0, 0000, false)) {
233// 0, 0007, false)) {
San Mehata19b2502010-01-06 10:33:53 -0800234 LOGE("ASEC FAT mount failed (%s)", strerror(errno));
235 Loop::destroyByDevice(loopDevice);
236 unlink(asecFileName);
237 return -1;
238 }
239
240 return 0;
241}
242
243int VolumeManager::finalizeAsec(const char *id) {
244 char asecFileName[255];
245 char loopDevice[255];
246 char mountPoint[255];
247
248 snprintf(asecFileName, sizeof(asecFileName),
249 "/sdcard/android_secure/%s.asec", id);
250
251 if (Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
252 LOGE("Unable to finalize %s (%s)", id, strerror(errno));
253 return -1;
254 }
255
256 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
San Mehatfff0b472010-01-06 19:19:46 -0800257 // XXX:
258 if (Fat::doMount(loopDevice, mountPoint, true, true, 0, 0, 0227, false)) {
San Mehata19b2502010-01-06 10:33:53 -0800259 LOGE("ASEC finalize mount failed (%s)", strerror(errno));
260 return -1;
261 }
262
263 LOGD("ASEC %s finalized", id);
264 return 0;
265}
266
267int VolumeManager::destroyAsec(const char *id) {
268 char asecFileName[255];
269 char mountPoint[255];
270
271 snprintf(asecFileName, sizeof(asecFileName),
272 "/sdcard/android_secure/%s.asec", id);
273 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
274
275 if (isMountpointMounted(mountPoint)) {
276 int i, rc;
277 for (i = 0; i < 10; i++) {
278 rc = umount(mountPoint);
279 if (!rc) {
280 break;
281 }
282 if (rc && (errno == EINVAL || errno == ENOENT)) {
283 rc = 0;
284 break;
285 }
286 LOGW("ASEC %s unmount attempt %d failed (%s)",
287 id, i +1, strerror(errno));
288 usleep(1000 * 250);
289 }
290 if (rc) {
291 LOGE("Failed to unmount ASEC %s for destroy", id);
292 return -1;
293 }
294 }
295
296 char loopDevice[255];
297 if (!Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
298 Loop::destroyByDevice(loopDevice);
299 }
300
301 unlink(asecFileName);
302
303 LOGD("ASEC %s destroyed", id);
304 return 0;
305}
306
307int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
308 char asecFileName[255];
309 char mountPoint[255];
310
311 snprintf(asecFileName, sizeof(asecFileName),
312 "/sdcard/android_secure/%s.asec", id);
313 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
314
315 if (isMountpointMounted(mountPoint)) {
316 LOGE("ASEC %s already mounted", id);
317 errno = EBUSY;
318 return -1;
319 }
320
321 char loopDevice[255];
322 if (Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
323 if (Loop::getNextAvailable(loopDevice, sizeof(loopDevice))) {
324 LOGE("Unable to find loop device for ASEC mount");
325 return -1;
326 }
327
328 if (Loop::create(loopDevice, asecFileName)) {
329 LOGE("ASEC loop device creation failed (%s)", strerror(errno));
330 return -1;
331 }
332 }
333
334 if (mkdir(mountPoint, 0777)) {
335 LOGE("Mountpoint creation failed (%s)", strerror(errno));
336 return -1;
337 }
338
San Mehatfff0b472010-01-06 19:19:46 -0800339 if (Fat::doMount(loopDevice, mountPoint, true, false, ownerUid, 0,
San Mehatcff5ec32010-01-08 12:31:44 -0800340 0222, false)) {
341// 0227, false)) {
San Mehata19b2502010-01-06 10:33:53 -0800342 LOGE("ASEC mount failed (%s)", strerror(errno));
343 return -1;
344 }
345
346 LOGD("ASEC %s mounted", id);
347 return 0;
348}
349
San Mehat49e2bce2009-10-12 16:29:01 -0700350int VolumeManager::mountVolume(const char *label) {
351 Volume *v = lookupVolume(label);
352
353 if (!v) {
354 errno = ENOENT;
355 return -1;
356 }
357
San Mehata2677e42009-12-13 10:40:18 -0800358 return v->mountVol();
359}
360
361int VolumeManager::shareAvailable(const char *method, bool *avail) {
362
363 if (strcmp(method, "ums")) {
364 errno = ENOSYS;
365 return -1;
366 }
367
368 if (mUsbMassStorageConnected)
369 *avail = true;
370 else
371 *avail = false;
372 return 0;
373}
374
375int VolumeManager::simulate(const char *cmd, const char *arg) {
376
377 if (!strcmp(cmd, "ums")) {
378 if (!strcmp(arg, "connect")) {
379 notifyUmsConnected(true);
380 } else if (!strcmp(arg, "disconnect")) {
381 notifyUmsConnected(false);
382 } else {
383 errno = EINVAL;
384 return -1;
385 }
386 } else {
387 errno = EINVAL;
388 return -1;
389 }
390 return 0;
391}
392
393int VolumeManager::shareVolume(const char *label, const char *method) {
394 Volume *v = lookupVolume(label);
395
396 if (!v) {
397 errno = ENOENT;
398 return -1;
399 }
400
401 /*
402 * Eventually, we'll want to support additional share back-ends,
403 * some of which may work while the media is mounted. For now,
404 * we just support UMS
405 */
406 if (strcmp(method, "ums")) {
407 errno = ENOSYS;
408 return -1;
409 }
410
411 if (v->getState() == Volume::State_NoMedia) {
412 errno = ENODEV;
413 return -1;
414 }
415
San Mehat49e2bce2009-10-12 16:29:01 -0700416 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -0800417 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -0700418 errno = EBUSY;
419 return -1;
420 }
421
San Mehata2677e42009-12-13 10:40:18 -0800422 dev_t d = v->getDiskDevice();
423 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
424 // This volume does not support raw disk access
425 errno = EINVAL;
426 return -1;
427 }
428
429 int fd;
430 char nodepath[255];
431 snprintf(nodepath,
432 sizeof(nodepath), "/dev/block/vold/%d:%d",
433 MAJOR(d), MINOR(d));
434
San Mehat0cde53c2009-12-22 08:32:33 -0800435 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file",
436 O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800437 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
438 return -1;
439 }
440
441 if (write(fd, nodepath, strlen(nodepath)) < 0) {
442 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
443 close(fd);
444 return -1;
445 }
446
447 close(fd);
448 v->handleVolumeShared();
449 return 0;
450}
451
452int VolumeManager::unshareVolume(const char *label, const char *method) {
453 Volume *v = lookupVolume(label);
454
455 if (!v) {
456 errno = ENOENT;
457 return -1;
458 }
459
460 if (strcmp(method, "ums")) {
461 errno = ENOSYS;
462 return -1;
463 }
464
465 if (v->getState() != Volume::State_Shared) {
466 errno = EINVAL;
467 return -1;
468 }
469
470 dev_t d = v->getDiskDevice();
471
472 int fd;
473 char nodepath[255];
474 snprintf(nodepath,
475 sizeof(nodepath), "/dev/block/vold/%d:%d",
476 MAJOR(d), MINOR(d));
477
San Mehat0cde53c2009-12-22 08:32:33 -0800478 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file", O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800479 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
480 return -1;
481 }
482
483 char ch = 0;
484 if (write(fd, &ch, 1) < 0) {
485 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
486 close(fd);
487 return -1;
488 }
489
490 close(fd);
491 v->handleVolumeUnshared();
492 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -0700493}
494
495int VolumeManager::unmountVolume(const char *label) {
496 Volume *v = lookupVolume(label);
497
498 if (!v) {
499 errno = ENOENT;
500 return -1;
501 }
502
San Mehata2677e42009-12-13 10:40:18 -0800503 if (v->getState() == Volume::State_NoMedia) {
504 errno = ENODEV;
505 return -1;
506 }
507
San Mehat49e2bce2009-10-12 16:29:01 -0700508 if (v->getState() != Volume::State_Mounted) {
San Mehata2677e42009-12-13 10:40:18 -0800509 LOGW("Attempt to unmount volume which isn't mounted (%d)\n",
510 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -0700511 errno = EBUSY;
512 return -1;
513 }
514
San Mehata2677e42009-12-13 10:40:18 -0800515 return v->unmountVol();
San Mehat49e2bce2009-10-12 16:29:01 -0700516}
517
San Mehata2677e42009-12-13 10:40:18 -0800518/*
519 * Looks up a volume by it's label or mount-point
520 */
San Mehat49e2bce2009-10-12 16:29:01 -0700521Volume *VolumeManager::lookupVolume(const char *label) {
522 VolumeCollection::iterator i;
523
524 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -0800525 if (label[0] == '/') {
526 if (!strcmp(label, (*i)->getMountpoint()))
527 return (*i);
528 } else {
529 if (!strcmp(label, (*i)->getLabel()))
530 return (*i);
531 }
San Mehat49e2bce2009-10-12 16:29:01 -0700532 }
533 return NULL;
534}
San Mehata19b2502010-01-06 10:33:53 -0800535
536bool VolumeManager::isMountpointMounted(const char *mp)
537{
538 char device[256];
539 char mount_path[256];
540 char rest[256];
541 FILE *fp;
542 char line[1024];
543
544 if (!(fp = fopen("/proc/mounts", "r"))) {
545 LOGE("Error opening /proc/mounts (%s)", strerror(errno));
546 return false;
547 }
548
549 while(fgets(line, sizeof(line), fp)) {
550 line[strlen(line)-1] = '\0';
551 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
552 if (!strcmp(mount_path, mp)) {
553 fclose(fp);
554 return true;
555 }
556
557 }
558
559 fclose(fp);
560 return false;
561}
562