blob: 96a691ba2df4ec1dbc018b269f3135019efc9940 [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 Mehatb78a32c2010-01-10 13:02:12 -080039#include "Devmapper.h"
San Mehatf1b736b2009-10-10 17:22:08 -070040
San Mehat23969932010-01-09 07:08:06 -080041extern "C" void KillProcessesWithOpenFiles(const char *, int, int, int);
42
San Mehatf1b736b2009-10-10 17:22:08 -070043VolumeManager *VolumeManager::sInstance = NULL;
44
45VolumeManager *VolumeManager::Instance() {
46 if (!sInstance)
47 sInstance = new VolumeManager();
48 return sInstance;
49}
50
51VolumeManager::VolumeManager() {
52 mBlockDevices = new BlockDeviceCollection();
53 mVolumes = new VolumeCollection();
San Mehat88705162010-01-15 09:26:28 -080054 mActiveContainers = new AsecIdCollection();
San Mehatf1b736b2009-10-10 17:22:08 -070055 mBroadcaster = NULL;
San Mehata2677e42009-12-13 10:40:18 -080056 mUsbMassStorageConnected = false;
San Mehatf1b736b2009-10-10 17:22:08 -070057}
58
59VolumeManager::~VolumeManager() {
60 delete mBlockDevices;
San Mehat88705162010-01-15 09:26:28 -080061 delete mVolumes;
62 delete mActiveContainers;
San Mehatf1b736b2009-10-10 17:22:08 -070063}
64
65int VolumeManager::start() {
66 return 0;
67}
68
69int VolumeManager::stop() {
70 return 0;
71}
72
73int VolumeManager::addVolume(Volume *v) {
74 mVolumes->push_back(v);
75 return 0;
76}
77
San Mehata2677e42009-12-13 10:40:18 -080078void VolumeManager::notifyUmsConnected(bool connected) {
79 char msg[255];
80
81 if (connected) {
82 mUsbMassStorageConnected = true;
83 } else {
84 mUsbMassStorageConnected = false;
85 }
86 snprintf(msg, sizeof(msg), "Share method ums now %s",
87 (connected ? "available" : "unavailable"));
88
89 getBroadcaster()->sendBroadcast(ResponseCode::ShareAvailabilityChange,
90 msg, false);
91}
92
93void VolumeManager::handleSwitchEvent(NetlinkEvent *evt) {
San Mehat0cde53c2009-12-22 08:32:33 -080094 const char *devpath = evt->findParam("DEVPATH");
San Mehata2677e42009-12-13 10:40:18 -080095 const char *name = evt->findParam("SWITCH_NAME");
96 const char *state = evt->findParam("SWITCH_STATE");
97
San Mehat0cde53c2009-12-22 08:32:33 -080098 if (!name || !state) {
99 LOGW("Switch %s event missing name/state info", devpath);
100 return;
101 }
102
San Mehata2677e42009-12-13 10:40:18 -0800103 if (!strcmp(name, "usb_mass_storage")) {
104
105 if (!strcmp(state, "online")) {
106 notifyUmsConnected(true);
107 } else {
108 notifyUmsConnected(false);
109 }
110 } else {
111 LOGW("Ignoring unknown switch '%s'", name);
112 }
113}
114
San Mehatfd7f5872009-10-12 11:32:47 -0700115void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
116 const char *devpath = evt->findParam("DEVPATH");
San Mehatf1b736b2009-10-10 17:22:08 -0700117
San Mehatfd7f5872009-10-12 11:32:47 -0700118 /* Lookup a volume to handle this device */
San Mehatf1b736b2009-10-10 17:22:08 -0700119 VolumeCollection::iterator it;
120 bool hit = false;
121 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
San Mehatfd7f5872009-10-12 11:32:47 -0700122 if (!(*it)->handleBlockEvent(evt)) {
San Mehata2677e42009-12-13 10:40:18 -0800123#ifdef NETLINK_DEBUG
124 LOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
125#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700126 hit = true;
San Mehatf1b736b2009-10-10 17:22:08 -0700127 break;
128 }
129 }
130
131 if (!hit) {
San Mehata2677e42009-12-13 10:40:18 -0800132#ifdef NETLINK_DEBUG
San Mehatfd7f5872009-10-12 11:32:47 -0700133 LOGW("No volumes handled block event for '%s'", devpath);
San Mehata2677e42009-12-13 10:40:18 -0800134#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700135 }
136}
137
San Mehatf1b736b2009-10-10 17:22:08 -0700138int VolumeManager::listVolumes(SocketClient *cli) {
139 VolumeCollection::iterator i;
140
141 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
142 char *buffer;
143 asprintf(&buffer, "%s %s %d",
144 (*i)->getLabel(), (*i)->getMountpoint(),
145 (*i)->getState());
San Mehata2677e42009-12-13 10:40:18 -0800146 cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
San Mehatf1b736b2009-10-10 17:22:08 -0700147 free(buffer);
148 }
San Mehata2677e42009-12-13 10:40:18 -0800149 cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
San Mehatf1b736b2009-10-10 17:22:08 -0700150 return 0;
151}
San Mehat49e2bce2009-10-12 16:29:01 -0700152
San Mehata2677e42009-12-13 10:40:18 -0800153int VolumeManager::formatVolume(const char *label) {
154 Volume *v = lookupVolume(label);
155
156 if (!v) {
157 errno = ENOENT;
158 return -1;
159 }
160
161 return v->formatVol();
162}
163
San Mehata19b2502010-01-06 10:33:53 -0800164int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
165 char mountPoint[255];
166
167 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
San Mehata19b2502010-01-06 10:33:53 -0800168 snprintf(buffer, maxlen, "/asec/%s", id);
169 return 0;
170}
171
San Mehat8b8f71b2010-01-11 09:17:25 -0800172int VolumeManager::createAsec(const char *id, unsigned int numSectors,
San Mehata19b2502010-01-06 10:33:53 -0800173 const char *fstype, const char *key, int ownerUid) {
174
175 mkdir("/sdcard/android_secure", 0777);
176
177 if (lookupVolume(id)) {
178 LOGE("ASEC volume '%s' currently exists", id);
179 errno = EADDRINUSE;
180 return -1;
181 }
182
183 char asecFileName[255];
184 snprintf(asecFileName, sizeof(asecFileName),
185 "/sdcard/android_secure/%s.asec", id);
186
187 if (!access(asecFileName, F_OK)) {
188 LOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
189 asecFileName, strerror(errno));
190 errno = EADDRINUSE;
191 return -1;
192 }
193
San Mehat8b8f71b2010-01-11 09:17:25 -0800194 if (Loop::createImageFile(asecFileName, numSectors)) {
San Mehata19b2502010-01-06 10:33:53 -0800195 LOGE("ASEC image file creation failed (%s)", strerror(errno));
196 return -1;
197 }
198
199 char loopDevice[255];
San Mehat8da6bcb2010-01-09 12:24:05 -0800200 if (Loop::create(asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800201 LOGE("ASEC loop device creation failed (%s)", strerror(errno));
202 unlink(asecFileName);
203 return -1;
204 }
205
San Mehatb78a32c2010-01-10 13:02:12 -0800206 char dmDevice[255];
207 bool cleanupDm = false;
San Mehata19b2502010-01-06 10:33:53 -0800208
San Mehatb78a32c2010-01-10 13:02:12 -0800209 if (strcmp(key, "none")) {
San Mehat8b8f71b2010-01-11 09:17:25 -0800210 if (Devmapper::create(id, loopDevice, key, numSectors, dmDevice,
San Mehatb78a32c2010-01-10 13:02:12 -0800211 sizeof(dmDevice))) {
212 LOGE("ASEC device mapping failed (%s)", strerror(errno));
213 Loop::destroyByDevice(loopDevice);
214 unlink(asecFileName);
215 return -1;
216 }
217 cleanupDm = true;
218 } else {
219 strcpy(dmDevice, loopDevice);
220 }
221
222 if (Fat::format(dmDevice)) {
San Mehata19b2502010-01-06 10:33:53 -0800223 LOGE("ASEC FAT format failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800224 if (cleanupDm) {
225 Devmapper::destroy(id);
226 }
San Mehata19b2502010-01-06 10:33:53 -0800227 Loop::destroyByDevice(loopDevice);
228 unlink(asecFileName);
229 return -1;
230 }
231
232 char mountPoint[255];
233
234 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
235 if (mkdir(mountPoint, 0777)) {
San Mehateb13a902010-01-07 12:12:50 -0800236 if (errno != EEXIST) {
237 LOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800238 if (cleanupDm) {
239 Devmapper::destroy(id);
240 }
San Mehateb13a902010-01-07 12:12:50 -0800241 Loop::destroyByDevice(loopDevice);
242 unlink(asecFileName);
243 return -1;
244 }
San Mehata19b2502010-01-06 10:33:53 -0800245 }
246
San Mehatb78a32c2010-01-10 13:02:12 -0800247 if (Fat::doMount(dmDevice, mountPoint, false, false, ownerUid,
San Mehatcff5ec32010-01-08 12:31:44 -0800248 0, 0000, false)) {
249// 0, 0007, false)) {
San Mehata19b2502010-01-06 10:33:53 -0800250 LOGE("ASEC FAT mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800251 if (cleanupDm) {
252 Devmapper::destroy(id);
253 }
San Mehata19b2502010-01-06 10:33:53 -0800254 Loop::destroyByDevice(loopDevice);
255 unlink(asecFileName);
256 return -1;
257 }
San Mehat88705162010-01-15 09:26:28 -0800258
259 mActiveContainers->push_back(strdup(id));
San Mehata19b2502010-01-06 10:33:53 -0800260 return 0;
261}
262
263int VolumeManager::finalizeAsec(const char *id) {
264 char asecFileName[255];
265 char loopDevice[255];
266 char mountPoint[255];
267
268 snprintf(asecFileName, sizeof(asecFileName),
269 "/sdcard/android_secure/%s.asec", id);
270
271 if (Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
272 LOGE("Unable to finalize %s (%s)", id, strerror(errno));
273 return -1;
274 }
275
276 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
San Mehatfff0b472010-01-06 19:19:46 -0800277 // XXX:
278 if (Fat::doMount(loopDevice, mountPoint, true, true, 0, 0, 0227, false)) {
San Mehata19b2502010-01-06 10:33:53 -0800279 LOGE("ASEC finalize mount failed (%s)", strerror(errno));
280 return -1;
281 }
282
283 LOGD("ASEC %s finalized", id);
284 return 0;
285}
286
San Mehat048b0802010-01-23 08:17:06 -0800287int VolumeManager::renameAsec(const char *id1, const char *id2) {
288 char *asecFilename1;
289 char *asecFilename2;
290 char mountPoint[255];
291
292 asprintf(&asecFilename1, "/sdcard/android_secure/%s.asec", id1);
293 asprintf(&asecFilename2, "/sdcard/android_secure/%s.asec", id2);
294
295 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id1);
296 if (isMountpointMounted(mountPoint)) {
297 LOGW("Rename attempt when src mounted");
298 errno = EBUSY;
299 goto out_err;
300 }
301
302 if (!access(asecFilename2, F_OK)) {
303 LOGE("Rename attempt when dst exists");
304 errno = EADDRINUSE;
305 goto out_err;
306 }
307
308 if (rename(asecFilename1, asecFilename2)) {
309 LOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
310 goto out_err;
311 }
312
313 free(asecFilename1);
314 free(asecFilename2);
315 return 0;
316
317out_err:
318 free(asecFilename1);
319 free(asecFilename2);
320 return -1;
321}
322
San Mehatb78a32c2010-01-10 13:02:12 -0800323int VolumeManager::unmountAsec(const char *id) {
San Mehata19b2502010-01-06 10:33:53 -0800324 char asecFileName[255];
325 char mountPoint[255];
326
327 snprintf(asecFileName, sizeof(asecFileName),
328 "/sdcard/android_secure/%s.asec", id);
329 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
330
San Mehat0586d542010-01-12 15:38:59 -0800331 if (!isMountpointMounted(mountPoint)) {
San Mehatb78a32c2010-01-10 13:02:12 -0800332 LOGE("Unmount request for ASEC %s when not mounted", id);
333 errno = EINVAL;
334 return -1;
335 }
San Mehat23969932010-01-09 07:08:06 -0800336
San Mehatb78a32c2010-01-10 13:02:12 -0800337 int i, rc;
338 for (i = 0; i < 10; i++) {
339 rc = umount(mountPoint);
340 if (!rc) {
341 break;
San Mehata19b2502010-01-06 10:33:53 -0800342 }
San Mehatb78a32c2010-01-10 13:02:12 -0800343 if (rc && (errno == EINVAL || errno == ENOENT)) {
344 rc = 0;
345 break;
San Mehata19b2502010-01-06 10:33:53 -0800346 }
San Mehatb78a32c2010-01-10 13:02:12 -0800347 LOGW("ASEC %s unmount attempt %d failed (%s)",
348 id, i +1, strerror(errno));
349
350 if (i >= 5) {
351 KillProcessesWithOpenFiles(mountPoint, (i < 7 ? 0 : 1),
352 NULL, 0);
353 }
354 usleep(1000 * 250);
355 }
356
357 if (rc) {
358 LOGE("Failed to unmount ASEC %s", id);
359 return -1;
360 }
361
San Mehatf5c61982010-02-03 11:04:46 -0800362 if (rmdir(mountPoint)) {
363 LOGE("Failed to rmdir mountpoint (%s)", strerror(errno));
364 }
San Mehat88705162010-01-15 09:26:28 -0800365
San Mehatb78a32c2010-01-10 13:02:12 -0800366 if (Devmapper::destroy(id) && errno != ENXIO) {
367 LOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800368 }
369
370 char loopDevice[255];
371 if (!Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
372 Loop::destroyByDevice(loopDevice);
373 }
San Mehat88705162010-01-15 09:26:28 -0800374
375 AsecIdCollection::iterator it;
376 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
377 if (!strcmp(*it, id)) {
378 free(*it);
379 mActiveContainers->erase(it);
380 break;
381 }
382 }
383 if (it == mActiveContainers->end()) {
384 LOGW("mActiveContainers is inconsistent!");
385 }
San Mehatb78a32c2010-01-10 13:02:12 -0800386 return 0;
387}
388
389int VolumeManager::destroyAsec(const char *id) {
390 char asecFileName[255];
391 char mountPoint[255];
392
393 snprintf(asecFileName, sizeof(asecFileName),
394 "/sdcard/android_secure/%s.asec", id);
395 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
396
San Mehat0586d542010-01-12 15:38:59 -0800397 if (isMountpointMounted(mountPoint)) {
San Mehat68f8ebd2010-01-23 07:21:21 -0800398 LOGD("Unmounting container before destroy");
San Mehat0586d542010-01-12 15:38:59 -0800399 if (unmountAsec(id)) {
400 LOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
401 return -1;
402 }
403 }
San Mehata19b2502010-01-06 10:33:53 -0800404
San Mehat0586d542010-01-12 15:38:59 -0800405 if (unlink(asecFileName)) {
San Mehat68f8ebd2010-01-23 07:21:21 -0800406 LOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800407 return -1;
408 }
San Mehata19b2502010-01-06 10:33:53 -0800409
410 LOGD("ASEC %s destroyed", id);
411 return 0;
412}
413
414int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
415 char asecFileName[255];
416 char mountPoint[255];
417
418 snprintf(asecFileName, sizeof(asecFileName),
419 "/sdcard/android_secure/%s.asec", id);
420 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
421
422 if (isMountpointMounted(mountPoint)) {
423 LOGE("ASEC %s already mounted", id);
424 errno = EBUSY;
425 return -1;
426 }
427
428 char loopDevice[255];
429 if (Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat8da6bcb2010-01-09 12:24:05 -0800430 if (Loop::create(asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800431 LOGE("ASEC loop device creation failed (%s)", strerror(errno));
432 return -1;
433 }
San Mehatb78a32c2010-01-10 13:02:12 -0800434 LOGD("New loop device created at %s", loopDevice);
435 } else {
436 LOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
437 }
438
439 char dmDevice[255];
440 bool cleanupDm = false;
441 if (strcmp(key, "none")) {
442 if (Devmapper::lookupActive(id, dmDevice, sizeof(dmDevice))) {
443 unsigned int nr_sec = 0;
444 int fd;
445
446 if ((fd = open(loopDevice, O_RDWR)) < 0) {
447 LOGE("Failed to open loopdevice (%s)", strerror(errno));
448 Loop::destroyByDevice(loopDevice);
449 return -1;
450 }
451
452 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
453 LOGE("Failed to get loop size (%s)", strerror(errno));
454 Loop::destroyByDevice(loopDevice);
455 close(fd);
456 return -1;
457 }
458 close(fd);
San Mehat8b8f71b2010-01-11 09:17:25 -0800459 if (Devmapper::create(id, loopDevice, key, nr_sec,
San Mehatb78a32c2010-01-10 13:02:12 -0800460 dmDevice, sizeof(dmDevice))) {
461 LOGE("ASEC device mapping failed (%s)", strerror(errno));
462 Loop::destroyByDevice(loopDevice);
463 return -1;
464 }
465 LOGD("New devmapper instance created at %s", dmDevice);
466 } else {
467 LOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
468 }
469 cleanupDm = true;
470 } else {
471 strcpy(dmDevice, loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800472 }
473
474 if (mkdir(mountPoint, 0777)) {
San Mehatb78a32c2010-01-10 13:02:12 -0800475 if (errno != EEXIST) {
476 LOGE("Mountpoint creation failed (%s)", strerror(errno));
477 if (cleanupDm) {
478 Devmapper::destroy(id);
479 }
480 Loop::destroyByDevice(loopDevice);
481 return -1;
482 }
San Mehata19b2502010-01-06 10:33:53 -0800483 }
484
San Mehatb78a32c2010-01-10 13:02:12 -0800485 if (Fat::doMount(dmDevice, mountPoint, true, false, ownerUid, 0,
San Mehatcff5ec32010-01-08 12:31:44 -0800486 0222, false)) {
487// 0227, false)) {
San Mehata19b2502010-01-06 10:33:53 -0800488 LOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800489 if (cleanupDm) {
490 Devmapper::destroy(id);
491 }
492 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800493 return -1;
494 }
495
San Mehat88705162010-01-15 09:26:28 -0800496 mActiveContainers->push_back(strdup(id));
San Mehata19b2502010-01-06 10:33:53 -0800497 LOGD("ASEC %s mounted", id);
498 return 0;
499}
500
San Mehat49e2bce2009-10-12 16:29:01 -0700501int VolumeManager::mountVolume(const char *label) {
502 Volume *v = lookupVolume(label);
503
504 if (!v) {
505 errno = ENOENT;
506 return -1;
507 }
508
San Mehata2677e42009-12-13 10:40:18 -0800509 return v->mountVol();
510}
511
512int VolumeManager::shareAvailable(const char *method, bool *avail) {
513
514 if (strcmp(method, "ums")) {
515 errno = ENOSYS;
516 return -1;
517 }
518
519 if (mUsbMassStorageConnected)
520 *avail = true;
521 else
522 *avail = false;
523 return 0;
524}
525
San Mehateba65e92010-01-29 05:15:16 -0800526int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
527 Volume *v = lookupVolume(label);
528
529 if (!v) {
530 errno = ENOENT;
531 return -1;
532 }
533
534 if (strcmp(method, "ums")) {
535 errno = ENOSYS;
536 return -1;
537 }
538
539 if (v->getState() != Volume::State_Shared) {
540 *enabled = true;
541 } else {
542 *enabled = false;
543 }
544 return 0;
545}
546
San Mehata2677e42009-12-13 10:40:18 -0800547int VolumeManager::simulate(const char *cmd, const char *arg) {
548
549 if (!strcmp(cmd, "ums")) {
550 if (!strcmp(arg, "connect")) {
551 notifyUmsConnected(true);
552 } else if (!strcmp(arg, "disconnect")) {
553 notifyUmsConnected(false);
554 } else {
555 errno = EINVAL;
556 return -1;
557 }
558 } else {
559 errno = EINVAL;
560 return -1;
561 }
562 return 0;
563}
564
565int VolumeManager::shareVolume(const char *label, const char *method) {
566 Volume *v = lookupVolume(label);
567
568 if (!v) {
569 errno = ENOENT;
570 return -1;
571 }
572
573 /*
574 * Eventually, we'll want to support additional share back-ends,
575 * some of which may work while the media is mounted. For now,
576 * we just support UMS
577 */
578 if (strcmp(method, "ums")) {
579 errno = ENOSYS;
580 return -1;
581 }
582
583 if (v->getState() == Volume::State_NoMedia) {
584 errno = ENODEV;
585 return -1;
586 }
587
San Mehat49e2bce2009-10-12 16:29:01 -0700588 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -0800589 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -0700590 errno = EBUSY;
591 return -1;
592 }
593
San Mehata2677e42009-12-13 10:40:18 -0800594 dev_t d = v->getDiskDevice();
595 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
596 // This volume does not support raw disk access
597 errno = EINVAL;
598 return -1;
599 }
600
601 int fd;
602 char nodepath[255];
603 snprintf(nodepath,
604 sizeof(nodepath), "/dev/block/vold/%d:%d",
605 MAJOR(d), MINOR(d));
606
San Mehat0cde53c2009-12-22 08:32:33 -0800607 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file",
608 O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800609 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
610 return -1;
611 }
612
613 if (write(fd, nodepath, strlen(nodepath)) < 0) {
614 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
615 close(fd);
616 return -1;
617 }
618
619 close(fd);
620 v->handleVolumeShared();
621 return 0;
622}
623
624int VolumeManager::unshareVolume(const char *label, const char *method) {
625 Volume *v = lookupVolume(label);
626
627 if (!v) {
628 errno = ENOENT;
629 return -1;
630 }
631
632 if (strcmp(method, "ums")) {
633 errno = ENOSYS;
634 return -1;
635 }
636
637 if (v->getState() != Volume::State_Shared) {
638 errno = EINVAL;
639 return -1;
640 }
641
642 dev_t d = v->getDiskDevice();
643
644 int fd;
645 char nodepath[255];
646 snprintf(nodepath,
647 sizeof(nodepath), "/dev/block/vold/%d:%d",
648 MAJOR(d), MINOR(d));
649
San Mehat0cde53c2009-12-22 08:32:33 -0800650 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file", O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800651 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
652 return -1;
653 }
654
655 char ch = 0;
656 if (write(fd, &ch, 1) < 0) {
657 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
658 close(fd);
659 return -1;
660 }
661
662 close(fd);
663 v->handleVolumeUnshared();
664 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -0700665}
666
667int VolumeManager::unmountVolume(const char *label) {
668 Volume *v = lookupVolume(label);
669
670 if (!v) {
671 errno = ENOENT;
672 return -1;
673 }
674
San Mehata2677e42009-12-13 10:40:18 -0800675 if (v->getState() == Volume::State_NoMedia) {
676 errno = ENODEV;
677 return -1;
678 }
679
San Mehat49e2bce2009-10-12 16:29:01 -0700680 if (v->getState() != Volume::State_Mounted) {
San Mehata2677e42009-12-13 10:40:18 -0800681 LOGW("Attempt to unmount volume which isn't mounted (%d)\n",
682 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -0700683 errno = EBUSY;
684 return -1;
685 }
686
San Mehat88705162010-01-15 09:26:28 -0800687 while(mActiveContainers->size()) {
688 AsecIdCollection::iterator it = mActiveContainers->begin();
689 LOGI("Unmounting ASEC %s (dependant on %s)", *it, v->getMountpoint());
690 if (unmountAsec(*it)) {
691 LOGE("Failed to unmount ASEC %s (%s) - unmount of %s may fail!", *it,
692 strerror(errno), v->getMountpoint());
693 }
694 }
695
San Mehata2677e42009-12-13 10:40:18 -0800696 return v->unmountVol();
San Mehat49e2bce2009-10-12 16:29:01 -0700697}
698
San Mehata2677e42009-12-13 10:40:18 -0800699/*
700 * Looks up a volume by it's label or mount-point
701 */
San Mehat49e2bce2009-10-12 16:29:01 -0700702Volume *VolumeManager::lookupVolume(const char *label) {
703 VolumeCollection::iterator i;
704
705 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -0800706 if (label[0] == '/') {
707 if (!strcmp(label, (*i)->getMountpoint()))
708 return (*i);
709 } else {
710 if (!strcmp(label, (*i)->getLabel()))
711 return (*i);
712 }
San Mehat49e2bce2009-10-12 16:29:01 -0700713 }
714 return NULL;
715}
San Mehata19b2502010-01-06 10:33:53 -0800716
717bool VolumeManager::isMountpointMounted(const char *mp)
718{
719 char device[256];
720 char mount_path[256];
721 char rest[256];
722 FILE *fp;
723 char line[1024];
724
725 if (!(fp = fopen("/proc/mounts", "r"))) {
726 LOGE("Error opening /proc/mounts (%s)", strerror(errno));
727 return false;
728 }
729
730 while(fgets(line, sizeof(line), fp)) {
731 line[strlen(line)-1] = '\0';
732 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
733 if (!strcmp(mount_path, mp)) {
734 fclose(fp);
735 return true;
736 }
737
738 }
739
740 fclose(fp);
741 return false;
742}
743