blob: d778ce217183192c52847854e6a8434a47e6edc6 [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 Mehat8c940ef2010-02-13 14:19:53 -080041extern "C" void KillProcessesWithOpenFiles(const char *, int);
San Mehat23969932010-01-09 07:08:06 -080042
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 Mehat8c940ef2010-02-13 14:19:53 -0800323#define ASEC_UNMOUNT_RETRIES 10
San Mehatb78a32c2010-01-10 13:02:12 -0800324int VolumeManager::unmountAsec(const char *id) {
San Mehata19b2502010-01-06 10:33:53 -0800325 char asecFileName[255];
326 char mountPoint[255];
327
328 snprintf(asecFileName, sizeof(asecFileName),
329 "/sdcard/android_secure/%s.asec", id);
330 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
331
San Mehat0586d542010-01-12 15:38:59 -0800332 if (!isMountpointMounted(mountPoint)) {
San Mehatb78a32c2010-01-10 13:02:12 -0800333 LOGE("Unmount request for ASEC %s when not mounted", id);
334 errno = EINVAL;
335 return -1;
336 }
San Mehat23969932010-01-09 07:08:06 -0800337
San Mehatb78a32c2010-01-10 13:02:12 -0800338 int i, rc;
San Mehat8c940ef2010-02-13 14:19:53 -0800339 for (i = 1; i <= ASEC_UNMOUNT_RETRIES; i++) {
San Mehatb78a32c2010-01-10 13:02:12 -0800340 rc = umount(mountPoint);
341 if (!rc) {
342 break;
San Mehata19b2502010-01-06 10:33:53 -0800343 }
San Mehatb78a32c2010-01-10 13:02:12 -0800344 if (rc && (errno == EINVAL || errno == ENOENT)) {
345 rc = 0;
346 break;
San Mehata19b2502010-01-06 10:33:53 -0800347 }
San Mehatb78a32c2010-01-10 13:02:12 -0800348 LOGW("ASEC %s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -0800349 id, i, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800350
San Mehat8c940ef2010-02-13 14:19:53 -0800351 int action;
352 if (i > (ASEC_UNMOUNT_RETRIES - 2))
353 action = 2; // SIGKILL
354 else if (i > (ASEC_UNMOUNT_RETRIES - 3))
355 action = 1; // SIGHUP
356 else
357 action = 0; // Just complain
358
359 KillProcessesWithOpenFiles(mountPoint, action);
360 usleep(1000 * 1000);
San Mehatb78a32c2010-01-10 13:02:12 -0800361 }
362
363 if (rc) {
364 LOGE("Failed to unmount ASEC %s", id);
365 return -1;
366 }
367
San Mehatf5c61982010-02-03 11:04:46 -0800368 if (rmdir(mountPoint)) {
369 LOGE("Failed to rmdir mountpoint (%s)", strerror(errno));
370 }
San Mehat88705162010-01-15 09:26:28 -0800371
San Mehatb78a32c2010-01-10 13:02:12 -0800372 if (Devmapper::destroy(id) && errno != ENXIO) {
373 LOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800374 }
375
376 char loopDevice[255];
377 if (!Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
378 Loop::destroyByDevice(loopDevice);
379 }
San Mehat88705162010-01-15 09:26:28 -0800380
381 AsecIdCollection::iterator it;
382 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
383 if (!strcmp(*it, id)) {
384 free(*it);
385 mActiveContainers->erase(it);
386 break;
387 }
388 }
389 if (it == mActiveContainers->end()) {
390 LOGW("mActiveContainers is inconsistent!");
391 }
San Mehatb78a32c2010-01-10 13:02:12 -0800392 return 0;
393}
394
395int VolumeManager::destroyAsec(const char *id) {
396 char asecFileName[255];
397 char mountPoint[255];
398
399 snprintf(asecFileName, sizeof(asecFileName),
400 "/sdcard/android_secure/%s.asec", id);
401 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
402
San Mehat0586d542010-01-12 15:38:59 -0800403 if (isMountpointMounted(mountPoint)) {
San Mehat68f8ebd2010-01-23 07:21:21 -0800404 LOGD("Unmounting container before destroy");
San Mehat0586d542010-01-12 15:38:59 -0800405 if (unmountAsec(id)) {
406 LOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
407 return -1;
408 }
409 }
San Mehata19b2502010-01-06 10:33:53 -0800410
San Mehat0586d542010-01-12 15:38:59 -0800411 if (unlink(asecFileName)) {
San Mehat68f8ebd2010-01-23 07:21:21 -0800412 LOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800413 return -1;
414 }
San Mehata19b2502010-01-06 10:33:53 -0800415
416 LOGD("ASEC %s destroyed", id);
417 return 0;
418}
419
420int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
421 char asecFileName[255];
422 char mountPoint[255];
423
424 snprintf(asecFileName, sizeof(asecFileName),
425 "/sdcard/android_secure/%s.asec", id);
426 snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
427
428 if (isMountpointMounted(mountPoint)) {
429 LOGE("ASEC %s already mounted", id);
430 errno = EBUSY;
431 return -1;
432 }
433
434 char loopDevice[255];
435 if (Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat8da6bcb2010-01-09 12:24:05 -0800436 if (Loop::create(asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800437 LOGE("ASEC loop device creation failed (%s)", strerror(errno));
438 return -1;
439 }
San Mehatb78a32c2010-01-10 13:02:12 -0800440 LOGD("New loop device created at %s", loopDevice);
441 } else {
442 LOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
443 }
444
445 char dmDevice[255];
446 bool cleanupDm = false;
447 if (strcmp(key, "none")) {
448 if (Devmapper::lookupActive(id, dmDevice, sizeof(dmDevice))) {
449 unsigned int nr_sec = 0;
450 int fd;
451
452 if ((fd = open(loopDevice, O_RDWR)) < 0) {
453 LOGE("Failed to open loopdevice (%s)", strerror(errno));
454 Loop::destroyByDevice(loopDevice);
455 return -1;
456 }
457
458 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
459 LOGE("Failed to get loop size (%s)", strerror(errno));
460 Loop::destroyByDevice(loopDevice);
461 close(fd);
462 return -1;
463 }
464 close(fd);
San Mehat8b8f71b2010-01-11 09:17:25 -0800465 if (Devmapper::create(id, loopDevice, key, nr_sec,
San Mehatb78a32c2010-01-10 13:02:12 -0800466 dmDevice, sizeof(dmDevice))) {
467 LOGE("ASEC device mapping failed (%s)", strerror(errno));
468 Loop::destroyByDevice(loopDevice);
469 return -1;
470 }
471 LOGD("New devmapper instance created at %s", dmDevice);
472 } else {
473 LOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
474 }
475 cleanupDm = true;
476 } else {
477 strcpy(dmDevice, loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800478 }
479
480 if (mkdir(mountPoint, 0777)) {
San Mehatb78a32c2010-01-10 13:02:12 -0800481 if (errno != EEXIST) {
482 LOGE("Mountpoint creation failed (%s)", strerror(errno));
483 if (cleanupDm) {
484 Devmapper::destroy(id);
485 }
486 Loop::destroyByDevice(loopDevice);
487 return -1;
488 }
San Mehata19b2502010-01-06 10:33:53 -0800489 }
490
San Mehatb78a32c2010-01-10 13:02:12 -0800491 if (Fat::doMount(dmDevice, mountPoint, true, false, ownerUid, 0,
San Mehatcff5ec32010-01-08 12:31:44 -0800492 0222, false)) {
493// 0227, false)) {
San Mehata19b2502010-01-06 10:33:53 -0800494 LOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800495 if (cleanupDm) {
496 Devmapper::destroy(id);
497 }
498 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800499 return -1;
500 }
501
San Mehat88705162010-01-15 09:26:28 -0800502 mActiveContainers->push_back(strdup(id));
San Mehata19b2502010-01-06 10:33:53 -0800503 LOGD("ASEC %s mounted", id);
504 return 0;
505}
506
San Mehat49e2bce2009-10-12 16:29:01 -0700507int VolumeManager::mountVolume(const char *label) {
508 Volume *v = lookupVolume(label);
509
510 if (!v) {
511 errno = ENOENT;
512 return -1;
513 }
514
San Mehata2677e42009-12-13 10:40:18 -0800515 return v->mountVol();
516}
517
518int VolumeManager::shareAvailable(const char *method, bool *avail) {
519
520 if (strcmp(method, "ums")) {
521 errno = ENOSYS;
522 return -1;
523 }
524
525 if (mUsbMassStorageConnected)
526 *avail = true;
527 else
528 *avail = false;
529 return 0;
530}
531
San Mehateba65e92010-01-29 05:15:16 -0800532int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
533 Volume *v = lookupVolume(label);
534
535 if (!v) {
536 errno = ENOENT;
537 return -1;
538 }
539
540 if (strcmp(method, "ums")) {
541 errno = ENOSYS;
542 return -1;
543 }
544
545 if (v->getState() != Volume::State_Shared) {
San Mehateba65e92010-01-29 05:15:16 -0800546 *enabled = false;
San Mehatb9aed742010-02-04 15:07:01 -0800547 } else {
548 *enabled = true;
San Mehateba65e92010-01-29 05:15:16 -0800549 }
550 return 0;
551}
552
San Mehata2677e42009-12-13 10:40:18 -0800553int VolumeManager::simulate(const char *cmd, const char *arg) {
554
555 if (!strcmp(cmd, "ums")) {
556 if (!strcmp(arg, "connect")) {
557 notifyUmsConnected(true);
558 } else if (!strcmp(arg, "disconnect")) {
559 notifyUmsConnected(false);
560 } else {
561 errno = EINVAL;
562 return -1;
563 }
564 } else {
565 errno = EINVAL;
566 return -1;
567 }
568 return 0;
569}
570
571int VolumeManager::shareVolume(const char *label, const char *method) {
572 Volume *v = lookupVolume(label);
573
574 if (!v) {
575 errno = ENOENT;
576 return -1;
577 }
578
579 /*
580 * Eventually, we'll want to support additional share back-ends,
581 * some of which may work while the media is mounted. For now,
582 * we just support UMS
583 */
584 if (strcmp(method, "ums")) {
585 errno = ENOSYS;
586 return -1;
587 }
588
589 if (v->getState() == Volume::State_NoMedia) {
590 errno = ENODEV;
591 return -1;
592 }
593
San Mehat49e2bce2009-10-12 16:29:01 -0700594 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -0800595 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -0700596 errno = EBUSY;
597 return -1;
598 }
599
San Mehata2677e42009-12-13 10:40:18 -0800600 dev_t d = v->getDiskDevice();
601 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
602 // This volume does not support raw disk access
603 errno = EINVAL;
604 return -1;
605 }
606
607 int fd;
608 char nodepath[255];
609 snprintf(nodepath,
610 sizeof(nodepath), "/dev/block/vold/%d:%d",
611 MAJOR(d), MINOR(d));
612
San Mehat0cde53c2009-12-22 08:32:33 -0800613 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file",
614 O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800615 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
616 return -1;
617 }
618
619 if (write(fd, nodepath, strlen(nodepath)) < 0) {
620 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
621 close(fd);
622 return -1;
623 }
624
625 close(fd);
626 v->handleVolumeShared();
627 return 0;
628}
629
630int VolumeManager::unshareVolume(const char *label, const char *method) {
631 Volume *v = lookupVolume(label);
632
633 if (!v) {
634 errno = ENOENT;
635 return -1;
636 }
637
638 if (strcmp(method, "ums")) {
639 errno = ENOSYS;
640 return -1;
641 }
642
643 if (v->getState() != Volume::State_Shared) {
644 errno = EINVAL;
645 return -1;
646 }
647
648 dev_t d = v->getDiskDevice();
649
650 int fd;
651 char nodepath[255];
652 snprintf(nodepath,
653 sizeof(nodepath), "/dev/block/vold/%d:%d",
654 MAJOR(d), MINOR(d));
655
San Mehat0cde53c2009-12-22 08:32:33 -0800656 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file", O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800657 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
658 return -1;
659 }
660
661 char ch = 0;
662 if (write(fd, &ch, 1) < 0) {
663 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
664 close(fd);
665 return -1;
666 }
667
668 close(fd);
669 v->handleVolumeUnshared();
670 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -0700671}
672
673int VolumeManager::unmountVolume(const char *label) {
674 Volume *v = lookupVolume(label);
675
676 if (!v) {
677 errno = ENOENT;
678 return -1;
679 }
680
San Mehata2677e42009-12-13 10:40:18 -0800681 if (v->getState() == Volume::State_NoMedia) {
682 errno = ENODEV;
683 return -1;
684 }
685
San Mehat49e2bce2009-10-12 16:29:01 -0700686 if (v->getState() != Volume::State_Mounted) {
San Mehata2677e42009-12-13 10:40:18 -0800687 LOGW("Attempt to unmount volume which isn't mounted (%d)\n",
688 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -0700689 errno = EBUSY;
690 return -1;
691 }
692
San Mehat88705162010-01-15 09:26:28 -0800693 while(mActiveContainers->size()) {
694 AsecIdCollection::iterator it = mActiveContainers->begin();
695 LOGI("Unmounting ASEC %s (dependant on %s)", *it, v->getMountpoint());
696 if (unmountAsec(*it)) {
697 LOGE("Failed to unmount ASEC %s (%s) - unmount of %s may fail!", *it,
698 strerror(errno), v->getMountpoint());
699 }
700 }
701
San Mehata2677e42009-12-13 10:40:18 -0800702 return v->unmountVol();
San Mehat49e2bce2009-10-12 16:29:01 -0700703}
704
San Mehata2677e42009-12-13 10:40:18 -0800705/*
706 * Looks up a volume by it's label or mount-point
707 */
San Mehat49e2bce2009-10-12 16:29:01 -0700708Volume *VolumeManager::lookupVolume(const char *label) {
709 VolumeCollection::iterator i;
710
711 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -0800712 if (label[0] == '/') {
713 if (!strcmp(label, (*i)->getMountpoint()))
714 return (*i);
715 } else {
716 if (!strcmp(label, (*i)->getLabel()))
717 return (*i);
718 }
San Mehat49e2bce2009-10-12 16:29:01 -0700719 }
720 return NULL;
721}
San Mehata19b2502010-01-06 10:33:53 -0800722
723bool VolumeManager::isMountpointMounted(const char *mp)
724{
725 char device[256];
726 char mount_path[256];
727 char rest[256];
728 FILE *fp;
729 char line[1024];
730
731 if (!(fp = fopen("/proc/mounts", "r"))) {
732 LOGE("Error opening /proc/mounts (%s)", strerror(errno));
733 return false;
734 }
735
736 while(fgets(line, sizeof(line), fp)) {
737 line[strlen(line)-1] = '\0';
738 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
739 if (!strcmp(mount_path, mp)) {
740 fclose(fp);
741 return true;
742 }
743
744 }
745
746 fclose(fp);
747 return false;
748}
749