blob: 40e3e1fb02b9f7a6c8146198d284a89c9cc553aa [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 Mehat88705162010-01-15 09:26:28 -0800362 unlink(mountPoint);
363
San Mehatb78a32c2010-01-10 13:02:12 -0800364 if (Devmapper::destroy(id) && errno != ENXIO) {
365 LOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800366 }
367
368 char loopDevice[255];
369 if (!Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
370 Loop::destroyByDevice(loopDevice);
371 }
San Mehat88705162010-01-15 09:26:28 -0800372
373 AsecIdCollection::iterator it;
374 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
375 if (!strcmp(*it, id)) {
376 free(*it);
377 mActiveContainers->erase(it);
378 break;
379 }
380 }
381 if (it == mActiveContainers->end()) {
382 LOGW("mActiveContainers is inconsistent!");
383 }
San Mehatb78a32c2010-01-10 13:02:12 -0800384 return 0;
385}
386
387int VolumeManager::destroyAsec(const char *id) {
388 char asecFileName[255];
389 char mountPoint[255];
390
391 snprintf(asecFileName, sizeof(asecFileName),
392 "/sdcard/android_secure/%s.asec", id);
393 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
394
San Mehat0586d542010-01-12 15:38:59 -0800395 if (isMountpointMounted(mountPoint)) {
San Mehat68f8ebd2010-01-23 07:21:21 -0800396 LOGD("Unmounting container before destroy");
San Mehat0586d542010-01-12 15:38:59 -0800397 if (unmountAsec(id)) {
398 LOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
399 return -1;
400 }
401 }
San Mehata19b2502010-01-06 10:33:53 -0800402
San Mehat0586d542010-01-12 15:38:59 -0800403 if (unlink(asecFileName)) {
San Mehat68f8ebd2010-01-23 07:21:21 -0800404 LOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800405 return -1;
406 }
San Mehata19b2502010-01-06 10:33:53 -0800407
408 LOGD("ASEC %s destroyed", id);
409 return 0;
410}
411
412int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
413 char asecFileName[255];
414 char mountPoint[255];
415
416 snprintf(asecFileName, sizeof(asecFileName),
417 "/sdcard/android_secure/%s.asec", id);
418 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
419
420 if (isMountpointMounted(mountPoint)) {
421 LOGE("ASEC %s already mounted", id);
422 errno = EBUSY;
423 return -1;
424 }
425
426 char loopDevice[255];
427 if (Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat8da6bcb2010-01-09 12:24:05 -0800428 if (Loop::create(asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800429 LOGE("ASEC loop device creation failed (%s)", strerror(errno));
430 return -1;
431 }
San Mehatb78a32c2010-01-10 13:02:12 -0800432 LOGD("New loop device created at %s", loopDevice);
433 } else {
434 LOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
435 }
436
437 char dmDevice[255];
438 bool cleanupDm = false;
439 if (strcmp(key, "none")) {
440 if (Devmapper::lookupActive(id, dmDevice, sizeof(dmDevice))) {
441 unsigned int nr_sec = 0;
442 int fd;
443
444 if ((fd = open(loopDevice, O_RDWR)) < 0) {
445 LOGE("Failed to open loopdevice (%s)", strerror(errno));
446 Loop::destroyByDevice(loopDevice);
447 return -1;
448 }
449
450 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
451 LOGE("Failed to get loop size (%s)", strerror(errno));
452 Loop::destroyByDevice(loopDevice);
453 close(fd);
454 return -1;
455 }
456 close(fd);
San Mehat8b8f71b2010-01-11 09:17:25 -0800457 if (Devmapper::create(id, loopDevice, key, nr_sec,
San Mehatb78a32c2010-01-10 13:02:12 -0800458 dmDevice, sizeof(dmDevice))) {
459 LOGE("ASEC device mapping failed (%s)", strerror(errno));
460 Loop::destroyByDevice(loopDevice);
461 return -1;
462 }
463 LOGD("New devmapper instance created at %s", dmDevice);
464 } else {
465 LOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
466 }
467 cleanupDm = true;
468 } else {
469 strcpy(dmDevice, loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800470 }
471
472 if (mkdir(mountPoint, 0777)) {
San Mehatb78a32c2010-01-10 13:02:12 -0800473 if (errno != EEXIST) {
474 LOGE("Mountpoint creation failed (%s)", strerror(errno));
475 if (cleanupDm) {
476 Devmapper::destroy(id);
477 }
478 Loop::destroyByDevice(loopDevice);
479 return -1;
480 }
San Mehata19b2502010-01-06 10:33:53 -0800481 }
482
San Mehatb78a32c2010-01-10 13:02:12 -0800483 if (Fat::doMount(dmDevice, mountPoint, true, false, ownerUid, 0,
San Mehatcff5ec32010-01-08 12:31:44 -0800484 0222, false)) {
485// 0227, false)) {
San Mehata19b2502010-01-06 10:33:53 -0800486 LOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800487 if (cleanupDm) {
488 Devmapper::destroy(id);
489 }
490 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800491 return -1;
492 }
493
San Mehat88705162010-01-15 09:26:28 -0800494 mActiveContainers->push_back(strdup(id));
San Mehata19b2502010-01-06 10:33:53 -0800495 LOGD("ASEC %s mounted", id);
496 return 0;
497}
498
San Mehat49e2bce2009-10-12 16:29:01 -0700499int VolumeManager::mountVolume(const char *label) {
500 Volume *v = lookupVolume(label);
501
502 if (!v) {
503 errno = ENOENT;
504 return -1;
505 }
506
San Mehata2677e42009-12-13 10:40:18 -0800507 return v->mountVol();
508}
509
510int VolumeManager::shareAvailable(const char *method, bool *avail) {
511
512 if (strcmp(method, "ums")) {
513 errno = ENOSYS;
514 return -1;
515 }
516
517 if (mUsbMassStorageConnected)
518 *avail = true;
519 else
520 *avail = false;
521 return 0;
522}
523
San Mehateba65e92010-01-29 05:15:16 -0800524int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
525 Volume *v = lookupVolume(label);
526
527 if (!v) {
528 errno = ENOENT;
529 return -1;
530 }
531
532 if (strcmp(method, "ums")) {
533 errno = ENOSYS;
534 return -1;
535 }
536
537 if (v->getState() != Volume::State_Shared) {
538 *enabled = true;
539 } else {
540 *enabled = false;
541 }
542 return 0;
543}
544
San Mehata2677e42009-12-13 10:40:18 -0800545int VolumeManager::simulate(const char *cmd, const char *arg) {
546
547 if (!strcmp(cmd, "ums")) {
548 if (!strcmp(arg, "connect")) {
549 notifyUmsConnected(true);
550 } else if (!strcmp(arg, "disconnect")) {
551 notifyUmsConnected(false);
552 } else {
553 errno = EINVAL;
554 return -1;
555 }
556 } else {
557 errno = EINVAL;
558 return -1;
559 }
560 return 0;
561}
562
563int VolumeManager::shareVolume(const char *label, const char *method) {
564 Volume *v = lookupVolume(label);
565
566 if (!v) {
567 errno = ENOENT;
568 return -1;
569 }
570
571 /*
572 * Eventually, we'll want to support additional share back-ends,
573 * some of which may work while the media is mounted. For now,
574 * we just support UMS
575 */
576 if (strcmp(method, "ums")) {
577 errno = ENOSYS;
578 return -1;
579 }
580
581 if (v->getState() == Volume::State_NoMedia) {
582 errno = ENODEV;
583 return -1;
584 }
585
San Mehat49e2bce2009-10-12 16:29:01 -0700586 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -0800587 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -0700588 errno = EBUSY;
589 return -1;
590 }
591
San Mehata2677e42009-12-13 10:40:18 -0800592 dev_t d = v->getDiskDevice();
593 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
594 // This volume does not support raw disk access
595 errno = EINVAL;
596 return -1;
597 }
598
599 int fd;
600 char nodepath[255];
601 snprintf(nodepath,
602 sizeof(nodepath), "/dev/block/vold/%d:%d",
603 MAJOR(d), MINOR(d));
604
San Mehat0cde53c2009-12-22 08:32:33 -0800605 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file",
606 O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800607 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
608 return -1;
609 }
610
611 if (write(fd, nodepath, strlen(nodepath)) < 0) {
612 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
613 close(fd);
614 return -1;
615 }
616
617 close(fd);
618 v->handleVolumeShared();
619 return 0;
620}
621
622int VolumeManager::unshareVolume(const char *label, const char *method) {
623 Volume *v = lookupVolume(label);
624
625 if (!v) {
626 errno = ENOENT;
627 return -1;
628 }
629
630 if (strcmp(method, "ums")) {
631 errno = ENOSYS;
632 return -1;
633 }
634
635 if (v->getState() != Volume::State_Shared) {
636 errno = EINVAL;
637 return -1;
638 }
639
640 dev_t d = v->getDiskDevice();
641
642 int fd;
643 char nodepath[255];
644 snprintf(nodepath,
645 sizeof(nodepath), "/dev/block/vold/%d:%d",
646 MAJOR(d), MINOR(d));
647
San Mehat0cde53c2009-12-22 08:32:33 -0800648 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file", O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800649 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
650 return -1;
651 }
652
653 char ch = 0;
654 if (write(fd, &ch, 1) < 0) {
655 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
656 close(fd);
657 return -1;
658 }
659
660 close(fd);
661 v->handleVolumeUnshared();
662 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -0700663}
664
665int VolumeManager::unmountVolume(const char *label) {
666 Volume *v = lookupVolume(label);
667
668 if (!v) {
669 errno = ENOENT;
670 return -1;
671 }
672
San Mehata2677e42009-12-13 10:40:18 -0800673 if (v->getState() == Volume::State_NoMedia) {
674 errno = ENODEV;
675 return -1;
676 }
677
San Mehat49e2bce2009-10-12 16:29:01 -0700678 if (v->getState() != Volume::State_Mounted) {
San Mehata2677e42009-12-13 10:40:18 -0800679 LOGW("Attempt to unmount volume which isn't mounted (%d)\n",
680 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -0700681 errno = EBUSY;
682 return -1;
683 }
684
San Mehat88705162010-01-15 09:26:28 -0800685 while(mActiveContainers->size()) {
686 AsecIdCollection::iterator it = mActiveContainers->begin();
687 LOGI("Unmounting ASEC %s (dependant on %s)", *it, v->getMountpoint());
688 if (unmountAsec(*it)) {
689 LOGE("Failed to unmount ASEC %s (%s) - unmount of %s may fail!", *it,
690 strerror(errno), v->getMountpoint());
691 }
692 }
693
San Mehata2677e42009-12-13 10:40:18 -0800694 return v->unmountVol();
San Mehat49e2bce2009-10-12 16:29:01 -0700695}
696
San Mehata2677e42009-12-13 10:40:18 -0800697/*
698 * Looks up a volume by it's label or mount-point
699 */
San Mehat49e2bce2009-10-12 16:29:01 -0700700Volume *VolumeManager::lookupVolume(const char *label) {
701 VolumeCollection::iterator i;
702
703 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -0800704 if (label[0] == '/') {
705 if (!strcmp(label, (*i)->getMountpoint()))
706 return (*i);
707 } else {
708 if (!strcmp(label, (*i)->getLabel()))
709 return (*i);
710 }
San Mehat49e2bce2009-10-12 16:29:01 -0700711 }
712 return NULL;
713}
San Mehata19b2502010-01-06 10:33:53 -0800714
715bool VolumeManager::isMountpointMounted(const char *mp)
716{
717 char device[256];
718 char mount_path[256];
719 char rest[256];
720 FILE *fp;
721 char line[1024];
722
723 if (!(fp = fopen("/proc/mounts", "r"))) {
724 LOGE("Error opening /proc/mounts (%s)", strerror(errno));
725 return false;
726 }
727
728 while(fgets(line, sizeof(line), fp)) {
729 line[strlen(line)-1] = '\0';
730 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
731 if (!strcmp(mount_path, mp)) {
732 fclose(fp);
733 return true;
734 }
735
736 }
737
738 fclose(fp);
739 return false;
740}
741