blob: ce0127553dc02eede2abdd4452951459c2577634 [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 Mehat586536c2010-02-16 17:12:00 -080040#include "Process.h"
San Mehat23969932010-01-09 07:08:06 -080041
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();
San Mehat88705162010-01-15 09:26:28 -080053 mActiveContainers = new AsecIdCollection();
San Mehatf1b736b2009-10-10 17:22:08 -070054 mBroadcaster = NULL;
San Mehata2677e42009-12-13 10:40:18 -080055 mUsbMassStorageConnected = false;
San Mehatf1b736b2009-10-10 17:22:08 -070056}
57
58VolumeManager::~VolumeManager() {
59 delete mBlockDevices;
San Mehat88705162010-01-15 09:26:28 -080060 delete mVolumes;
61 delete mActiveContainers;
San Mehatf1b736b2009-10-10 17:22:08 -070062}
63
64int VolumeManager::start() {
65 return 0;
66}
67
68int VolumeManager::stop() {
69 return 0;
70}
71
72int VolumeManager::addVolume(Volume *v) {
73 mVolumes->push_back(v);
74 return 0;
75}
76
San Mehata2677e42009-12-13 10:40:18 -080077void VolumeManager::notifyUmsConnected(bool connected) {
78 char msg[255];
79
80 if (connected) {
81 mUsbMassStorageConnected = true;
82 } else {
83 mUsbMassStorageConnected = false;
84 }
85 snprintf(msg, sizeof(msg), "Share method ums now %s",
86 (connected ? "available" : "unavailable"));
87
88 getBroadcaster()->sendBroadcast(ResponseCode::ShareAvailabilityChange,
89 msg, false);
90}
91
92void VolumeManager::handleSwitchEvent(NetlinkEvent *evt) {
San Mehat0cde53c2009-12-22 08:32:33 -080093 const char *devpath = evt->findParam("DEVPATH");
San Mehata2677e42009-12-13 10:40:18 -080094 const char *name = evt->findParam("SWITCH_NAME");
95 const char *state = evt->findParam("SWITCH_STATE");
96
San Mehat0cde53c2009-12-22 08:32:33 -080097 if (!name || !state) {
98 LOGW("Switch %s event missing name/state info", devpath);
99 return;
100 }
101
San Mehata2677e42009-12-13 10:40:18 -0800102 if (!strcmp(name, "usb_mass_storage")) {
103
104 if (!strcmp(state, "online")) {
105 notifyUmsConnected(true);
106 } else {
107 notifyUmsConnected(false);
108 }
109 } else {
110 LOGW("Ignoring unknown switch '%s'", name);
111 }
112}
113
San Mehatfd7f5872009-10-12 11:32:47 -0700114void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
115 const char *devpath = evt->findParam("DEVPATH");
San Mehatf1b736b2009-10-10 17:22:08 -0700116
San Mehatfd7f5872009-10-12 11:32:47 -0700117 /* Lookup a volume to handle this device */
San Mehatf1b736b2009-10-10 17:22:08 -0700118 VolumeCollection::iterator it;
119 bool hit = false;
120 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
San Mehatfd7f5872009-10-12 11:32:47 -0700121 if (!(*it)->handleBlockEvent(evt)) {
San Mehata2677e42009-12-13 10:40:18 -0800122#ifdef NETLINK_DEBUG
123 LOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
124#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700125 hit = true;
San Mehatf1b736b2009-10-10 17:22:08 -0700126 break;
127 }
128 }
129
130 if (!hit) {
San Mehata2677e42009-12-13 10:40:18 -0800131#ifdef NETLINK_DEBUG
San Mehatfd7f5872009-10-12 11:32:47 -0700132 LOGW("No volumes handled block event for '%s'", devpath);
San Mehata2677e42009-12-13 10:40:18 -0800133#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700134 }
135}
136
San Mehatf1b736b2009-10-10 17:22:08 -0700137int VolumeManager::listVolumes(SocketClient *cli) {
138 VolumeCollection::iterator i;
139
140 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
141 char *buffer;
142 asprintf(&buffer, "%s %s %d",
143 (*i)->getLabel(), (*i)->getMountpoint(),
144 (*i)->getState());
San Mehata2677e42009-12-13 10:40:18 -0800145 cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
San Mehatf1b736b2009-10-10 17:22:08 -0700146 free(buffer);
147 }
San Mehata2677e42009-12-13 10:40:18 -0800148 cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
San Mehatf1b736b2009-10-10 17:22:08 -0700149 return 0;
150}
San Mehat49e2bce2009-10-12 16:29:01 -0700151
San Mehata2677e42009-12-13 10:40:18 -0800152int VolumeManager::formatVolume(const char *label) {
153 Volume *v = lookupVolume(label);
154
155 if (!v) {
156 errno = ENOENT;
157 return -1;
158 }
159
160 return v->formatVol();
161}
162
San Mehata19b2502010-01-06 10:33:53 -0800163int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
San Mehata19b2502010-01-06 10:33:53 -0800164
San Mehat3bb60202010-02-19 18:14:36 -0800165 snprintf(buffer, maxlen, "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800166 return 0;
167}
168
San Mehat8b8f71b2010-01-11 09:17:25 -0800169int VolumeManager::createAsec(const char *id, unsigned int numSectors,
San Mehata19b2502010-01-06 10:33:53 -0800170 const char *fstype, const char *key, int ownerUid) {
171
San Mehatd31e3802010-02-18 08:37:45 -0800172 if (numSectors < ((1024*1024)/512)) {
173 LOGE("Invalid container size specified (%d sectors)", numSectors);
174 errno = EINVAL;
175 return -1;
176 }
177
San Mehata19b2502010-01-06 10:33:53 -0800178 if (lookupVolume(id)) {
San Mehat3bb60202010-02-19 18:14:36 -0800179 LOGE("ASEC id '%s' currently exists", id);
San Mehata19b2502010-01-06 10:33:53 -0800180 errno = EADDRINUSE;
181 return -1;
182 }
183
184 char asecFileName[255];
San Mehat3bb60202010-02-19 18:14:36 -0800185 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800186
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
San Mehata1091cb2010-02-28 20:17:20 -0800222 if (strcmp(fstype, "none")) {
223 if (strcmp(fstype, "fat")) {
224 LOGW("Unknown fstype '%s' specified for container", fstype);
San Mehatb78a32c2010-01-10 13:02:12 -0800225 }
San Mehata19b2502010-01-06 10:33:53 -0800226
San Mehata1091cb2010-02-28 20:17:20 -0800227 if (Fat::format(dmDevice)) {
228 LOGE("ASEC FAT format failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800229 if (cleanupDm) {
230 Devmapper::destroy(id);
231 }
San Mehateb13a902010-01-07 12:12:50 -0800232 Loop::destroyByDevice(loopDevice);
233 unlink(asecFileName);
234 return -1;
235 }
San Mehata1091cb2010-02-28 20:17:20 -0800236 char mountPoint[255];
San Mehata19b2502010-01-06 10:33:53 -0800237
San Mehata1091cb2010-02-28 20:17:20 -0800238 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
239 if (mkdir(mountPoint, 0777)) {
240 if (errno != EEXIST) {
241 LOGE("Mountpoint creation failed (%s)", strerror(errno));
242 if (cleanupDm) {
243 Devmapper::destroy(id);
244 }
245 Loop::destroyByDevice(loopDevice);
246 unlink(asecFileName);
247 return -1;
248 }
San Mehatb78a32c2010-01-10 13:02:12 -0800249 }
San Mehata1091cb2010-02-28 20:17:20 -0800250
251 if (Fat::doMount(dmDevice, mountPoint, false, false, ownerUid,
252 0, 0000, false)) {
253 LOGE("ASEC FAT mount failed (%s)", strerror(errno));
254 if (cleanupDm) {
255 Devmapper::destroy(id);
256 }
257 Loop::destroyByDevice(loopDevice);
258 unlink(asecFileName);
259 return -1;
260 }
261 } else {
262 LOGI("Created raw secure container %s (no filesystem)", id);
San Mehata19b2502010-01-06 10:33:53 -0800263 }
San Mehat88705162010-01-15 09:26:28 -0800264
265 mActiveContainers->push_back(strdup(id));
San Mehata19b2502010-01-06 10:33:53 -0800266 return 0;
267}
268
269int VolumeManager::finalizeAsec(const char *id) {
270 char asecFileName[255];
271 char loopDevice[255];
272 char mountPoint[255];
273
San Mehat3bb60202010-02-19 18:14:36 -0800274 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800275
276 if (Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
277 LOGE("Unable to finalize %s (%s)", id, strerror(errno));
278 return -1;
279 }
280
San Mehat3bb60202010-02-19 18:14:36 -0800281 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatfff0b472010-01-06 19:19:46 -0800282 // XXX:
283 if (Fat::doMount(loopDevice, mountPoint, true, true, 0, 0, 0227, false)) {
San Mehata19b2502010-01-06 10:33:53 -0800284 LOGE("ASEC finalize mount failed (%s)", strerror(errno));
285 return -1;
286 }
287
288 LOGD("ASEC %s finalized", id);
289 return 0;
290}
291
San Mehat048b0802010-01-23 08:17:06 -0800292int VolumeManager::renameAsec(const char *id1, const char *id2) {
293 char *asecFilename1;
294 char *asecFilename2;
295 char mountPoint[255];
296
San Mehat3bb60202010-02-19 18:14:36 -0800297 asprintf(&asecFilename1, "%s/%s.asec", Volume::SEC_ASECDIR, id1);
298 asprintf(&asecFilename2, "%s/%s.asec", Volume::SEC_ASECDIR, id2);
San Mehat048b0802010-01-23 08:17:06 -0800299
San Mehat3bb60202010-02-19 18:14:36 -0800300 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
San Mehat048b0802010-01-23 08:17:06 -0800301 if (isMountpointMounted(mountPoint)) {
302 LOGW("Rename attempt when src mounted");
303 errno = EBUSY;
304 goto out_err;
305 }
306
San Mehat96956ed2010-02-24 08:42:51 -0800307 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2);
308 if (isMountpointMounted(mountPoint)) {
309 LOGW("Rename attempt when dst mounted");
310 errno = EBUSY;
311 goto out_err;
312 }
313
San Mehat048b0802010-01-23 08:17:06 -0800314 if (!access(asecFilename2, F_OK)) {
315 LOGE("Rename attempt when dst exists");
316 errno = EADDRINUSE;
317 goto out_err;
318 }
319
320 if (rename(asecFilename1, asecFilename2)) {
321 LOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
322 goto out_err;
323 }
324
325 free(asecFilename1);
326 free(asecFilename2);
327 return 0;
328
329out_err:
330 free(asecFilename1);
331 free(asecFilename2);
332 return -1;
333}
334
San Mehat4ba89482010-02-18 09:00:18 -0800335#define ASEC_UNMOUNT_RETRIES 5
336int VolumeManager::unmountAsec(const char *id, bool force) {
San Mehata19b2502010-01-06 10:33:53 -0800337 char asecFileName[255];
338 char mountPoint[255];
339
San Mehat3bb60202010-02-19 18:14:36 -0800340 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
341 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800342
San Mehat0586d542010-01-12 15:38:59 -0800343 if (!isMountpointMounted(mountPoint)) {
San Mehatb78a32c2010-01-10 13:02:12 -0800344 LOGE("Unmount request for ASEC %s when not mounted", id);
345 errno = EINVAL;
346 return -1;
347 }
San Mehat23969932010-01-09 07:08:06 -0800348
San Mehatb78a32c2010-01-10 13:02:12 -0800349 int i, rc;
San Mehat8c940ef2010-02-13 14:19:53 -0800350 for (i = 1; i <= ASEC_UNMOUNT_RETRIES; i++) {
San Mehatb78a32c2010-01-10 13:02:12 -0800351 rc = umount(mountPoint);
352 if (!rc) {
353 break;
San Mehata19b2502010-01-06 10:33:53 -0800354 }
San Mehatb78a32c2010-01-10 13:02:12 -0800355 if (rc && (errno == EINVAL || errno == ENOENT)) {
San Mehat12f4b892010-02-24 11:43:22 -0800356 LOGI("Secure container %s unmounted OK", id);
San Mehatb78a32c2010-01-10 13:02:12 -0800357 rc = 0;
358 break;
San Mehata19b2502010-01-06 10:33:53 -0800359 }
San Mehatb78a32c2010-01-10 13:02:12 -0800360 LOGW("ASEC %s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -0800361 id, i, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800362
San Mehat4ba89482010-02-18 09:00:18 -0800363 int action = 0; // default is to just complain
364
365 if (force) {
366 if (i > (ASEC_UNMOUNT_RETRIES - 2))
367 action = 2; // SIGKILL
368 else if (i > (ASEC_UNMOUNT_RETRIES - 3))
369 action = 1; // SIGHUP
370 }
San Mehat8c940ef2010-02-13 14:19:53 -0800371
San Mehat586536c2010-02-16 17:12:00 -0800372 Process::killProcessesWithOpenFiles(mountPoint, action);
San Mehat8c940ef2010-02-13 14:19:53 -0800373 usleep(1000 * 1000);
San Mehatb78a32c2010-01-10 13:02:12 -0800374 }
375
376 if (rc) {
San Mehat4ba89482010-02-18 09:00:18 -0800377 errno = EBUSY;
378 LOGE("Failed to unmount container %s (%s)", id, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800379 return -1;
380 }
381
San Mehat12f4b892010-02-24 11:43:22 -0800382 int retries = 10;
383
384 while(retries--) {
385 if (!rmdir(mountPoint)) {
386 break;
387 }
388
389 LOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
390 usleep(1000 * 1000);
391 }
392
393 if (!retries) {
394 LOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
San Mehatf5c61982010-02-03 11:04:46 -0800395 }
San Mehat88705162010-01-15 09:26:28 -0800396
San Mehatb78a32c2010-01-10 13:02:12 -0800397 if (Devmapper::destroy(id) && errno != ENXIO) {
398 LOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800399 }
400
401 char loopDevice[255];
402 if (!Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
403 Loop::destroyByDevice(loopDevice);
404 }
San Mehat88705162010-01-15 09:26:28 -0800405
406 AsecIdCollection::iterator it;
407 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
408 if (!strcmp(*it, id)) {
409 free(*it);
410 mActiveContainers->erase(it);
411 break;
412 }
413 }
414 if (it == mActiveContainers->end()) {
415 LOGW("mActiveContainers is inconsistent!");
416 }
San Mehatb78a32c2010-01-10 13:02:12 -0800417 return 0;
418}
419
San Mehat4ba89482010-02-18 09:00:18 -0800420int VolumeManager::destroyAsec(const char *id, bool force) {
San Mehatb78a32c2010-01-10 13:02:12 -0800421 char asecFileName[255];
422 char mountPoint[255];
423
San Mehat3bb60202010-02-19 18:14:36 -0800424 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehat55013f72010-02-24 12:12:34 -0800425 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatb78a32c2010-01-10 13:02:12 -0800426
San Mehat0586d542010-01-12 15:38:59 -0800427 if (isMountpointMounted(mountPoint)) {
San Mehat68f8ebd2010-01-23 07:21:21 -0800428 LOGD("Unmounting container before destroy");
San Mehat4ba89482010-02-18 09:00:18 -0800429 if (unmountAsec(id, force)) {
San Mehat0586d542010-01-12 15:38:59 -0800430 LOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
431 return -1;
432 }
433 }
San Mehata19b2502010-01-06 10:33:53 -0800434
San Mehat0586d542010-01-12 15:38:59 -0800435 if (unlink(asecFileName)) {
San Mehat68f8ebd2010-01-23 07:21:21 -0800436 LOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800437 return -1;
438 }
San Mehata19b2502010-01-06 10:33:53 -0800439
440 LOGD("ASEC %s destroyed", id);
441 return 0;
442}
443
444int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
445 char asecFileName[255];
446 char mountPoint[255];
447
San Mehat3bb60202010-02-19 18:14:36 -0800448 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
449 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800450
451 if (isMountpointMounted(mountPoint)) {
452 LOGE("ASEC %s already mounted", id);
453 errno = EBUSY;
454 return -1;
455 }
456
457 char loopDevice[255];
458 if (Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat8da6bcb2010-01-09 12:24:05 -0800459 if (Loop::create(asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800460 LOGE("ASEC loop device creation failed (%s)", strerror(errno));
461 return -1;
462 }
San Mehatb78a32c2010-01-10 13:02:12 -0800463 LOGD("New loop device created at %s", loopDevice);
464 } else {
465 LOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
466 }
467
468 char dmDevice[255];
469 bool cleanupDm = false;
470 if (strcmp(key, "none")) {
471 if (Devmapper::lookupActive(id, dmDevice, sizeof(dmDevice))) {
472 unsigned int nr_sec = 0;
473 int fd;
474
475 if ((fd = open(loopDevice, O_RDWR)) < 0) {
476 LOGE("Failed to open loopdevice (%s)", strerror(errno));
477 Loop::destroyByDevice(loopDevice);
478 return -1;
479 }
480
481 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
482 LOGE("Failed to get loop size (%s)", strerror(errno));
483 Loop::destroyByDevice(loopDevice);
484 close(fd);
485 return -1;
486 }
487 close(fd);
San Mehat8b8f71b2010-01-11 09:17:25 -0800488 if (Devmapper::create(id, loopDevice, key, nr_sec,
San Mehatb78a32c2010-01-10 13:02:12 -0800489 dmDevice, sizeof(dmDevice))) {
490 LOGE("ASEC device mapping failed (%s)", strerror(errno));
491 Loop::destroyByDevice(loopDevice);
492 return -1;
493 }
494 LOGD("New devmapper instance created at %s", dmDevice);
495 } else {
496 LOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
497 }
498 cleanupDm = true;
499 } else {
500 strcpy(dmDevice, loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800501 }
502
503 if (mkdir(mountPoint, 0777)) {
San Mehatb78a32c2010-01-10 13:02:12 -0800504 if (errno != EEXIST) {
505 LOGE("Mountpoint creation failed (%s)", strerror(errno));
506 if (cleanupDm) {
507 Devmapper::destroy(id);
508 }
509 Loop::destroyByDevice(loopDevice);
510 return -1;
511 }
San Mehata19b2502010-01-06 10:33:53 -0800512 }
513
San Mehatb78a32c2010-01-10 13:02:12 -0800514 if (Fat::doMount(dmDevice, mountPoint, true, false, ownerUid, 0,
San Mehatcff5ec32010-01-08 12:31:44 -0800515 0222, false)) {
516// 0227, false)) {
San Mehata19b2502010-01-06 10:33:53 -0800517 LOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800518 if (cleanupDm) {
519 Devmapper::destroy(id);
520 }
521 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800522 return -1;
523 }
524
San Mehat88705162010-01-15 09:26:28 -0800525 mActiveContainers->push_back(strdup(id));
San Mehata19b2502010-01-06 10:33:53 -0800526 LOGD("ASEC %s mounted", id);
527 return 0;
528}
529
San Mehat49e2bce2009-10-12 16:29:01 -0700530int VolumeManager::mountVolume(const char *label) {
531 Volume *v = lookupVolume(label);
532
533 if (!v) {
534 errno = ENOENT;
535 return -1;
536 }
537
San Mehata2677e42009-12-13 10:40:18 -0800538 return v->mountVol();
539}
540
541int VolumeManager::shareAvailable(const char *method, bool *avail) {
542
543 if (strcmp(method, "ums")) {
544 errno = ENOSYS;
545 return -1;
546 }
547
548 if (mUsbMassStorageConnected)
549 *avail = true;
550 else
551 *avail = false;
552 return 0;
553}
554
San Mehateba65e92010-01-29 05:15:16 -0800555int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
556 Volume *v = lookupVolume(label);
557
558 if (!v) {
559 errno = ENOENT;
560 return -1;
561 }
562
563 if (strcmp(method, "ums")) {
564 errno = ENOSYS;
565 return -1;
566 }
567
568 if (v->getState() != Volume::State_Shared) {
San Mehateba65e92010-01-29 05:15:16 -0800569 *enabled = false;
San Mehatb9aed742010-02-04 15:07:01 -0800570 } else {
571 *enabled = true;
San Mehateba65e92010-01-29 05:15:16 -0800572 }
573 return 0;
574}
575
San Mehata2677e42009-12-13 10:40:18 -0800576int VolumeManager::simulate(const char *cmd, const char *arg) {
577
578 if (!strcmp(cmd, "ums")) {
579 if (!strcmp(arg, "connect")) {
580 notifyUmsConnected(true);
581 } else if (!strcmp(arg, "disconnect")) {
582 notifyUmsConnected(false);
583 } else {
584 errno = EINVAL;
585 return -1;
586 }
587 } else {
588 errno = EINVAL;
589 return -1;
590 }
591 return 0;
592}
593
594int VolumeManager::shareVolume(const char *label, const char *method) {
595 Volume *v = lookupVolume(label);
596
597 if (!v) {
598 errno = ENOENT;
599 return -1;
600 }
601
602 /*
603 * Eventually, we'll want to support additional share back-ends,
604 * some of which may work while the media is mounted. For now,
605 * we just support UMS
606 */
607 if (strcmp(method, "ums")) {
608 errno = ENOSYS;
609 return -1;
610 }
611
612 if (v->getState() == Volume::State_NoMedia) {
613 errno = ENODEV;
614 return -1;
615 }
616
San Mehat49e2bce2009-10-12 16:29:01 -0700617 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -0800618 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -0700619 errno = EBUSY;
620 return -1;
621 }
622
San Mehata2677e42009-12-13 10:40:18 -0800623 dev_t d = v->getDiskDevice();
624 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
625 // This volume does not support raw disk access
626 errno = EINVAL;
627 return -1;
628 }
629
630 int fd;
631 char nodepath[255];
632 snprintf(nodepath,
633 sizeof(nodepath), "/dev/block/vold/%d:%d",
634 MAJOR(d), MINOR(d));
635
San Mehat0cde53c2009-12-22 08:32:33 -0800636 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file",
637 O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800638 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
639 return -1;
640 }
641
642 if (write(fd, nodepath, strlen(nodepath)) < 0) {
643 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
644 close(fd);
645 return -1;
646 }
647
648 close(fd);
649 v->handleVolumeShared();
650 return 0;
651}
652
653int VolumeManager::unshareVolume(const char *label, const char *method) {
654 Volume *v = lookupVolume(label);
655
656 if (!v) {
657 errno = ENOENT;
658 return -1;
659 }
660
661 if (strcmp(method, "ums")) {
662 errno = ENOSYS;
663 return -1;
664 }
665
666 if (v->getState() != Volume::State_Shared) {
667 errno = EINVAL;
668 return -1;
669 }
670
671 dev_t d = v->getDiskDevice();
672
673 int fd;
674 char nodepath[255];
675 snprintf(nodepath,
676 sizeof(nodepath), "/dev/block/vold/%d:%d",
677 MAJOR(d), MINOR(d));
678
San Mehat0cde53c2009-12-22 08:32:33 -0800679 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file", O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800680 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
681 return -1;
682 }
683
684 char ch = 0;
685 if (write(fd, &ch, 1) < 0) {
686 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
687 close(fd);
688 return -1;
689 }
690
691 close(fd);
692 v->handleVolumeUnshared();
693 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -0700694}
695
San Mehat4ba89482010-02-18 09:00:18 -0800696int VolumeManager::unmountVolume(const char *label, bool force) {
San Mehat49e2bce2009-10-12 16:29:01 -0700697 Volume *v = lookupVolume(label);
698
699 if (!v) {
700 errno = ENOENT;
701 return -1;
702 }
703
San Mehata2677e42009-12-13 10:40:18 -0800704 if (v->getState() == Volume::State_NoMedia) {
705 errno = ENODEV;
706 return -1;
707 }
708
San Mehat49e2bce2009-10-12 16:29:01 -0700709 if (v->getState() != Volume::State_Mounted) {
San Mehata2677e42009-12-13 10:40:18 -0800710 LOGW("Attempt to unmount volume which isn't mounted (%d)\n",
711 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -0700712 errno = EBUSY;
713 return -1;
714 }
715
San Mehat88705162010-01-15 09:26:28 -0800716 while(mActiveContainers->size()) {
717 AsecIdCollection::iterator it = mActiveContainers->begin();
718 LOGI("Unmounting ASEC %s (dependant on %s)", *it, v->getMountpoint());
San Mehat4ba89482010-02-18 09:00:18 -0800719 if (unmountAsec(*it, force)) {
San Mehat12f4b892010-02-24 11:43:22 -0800720 LOGE("Failed to unmount ASEC %s (%s)", *it, strerror(errno));
San Mehat0e382532010-02-24 08:25:55 -0800721 return -1;
San Mehat88705162010-01-15 09:26:28 -0800722 }
723 }
724
San Mehat4ba89482010-02-18 09:00:18 -0800725 return v->unmountVol(force);
San Mehat49e2bce2009-10-12 16:29:01 -0700726}
727
San Mehata2677e42009-12-13 10:40:18 -0800728/*
729 * Looks up a volume by it's label or mount-point
730 */
San Mehat49e2bce2009-10-12 16:29:01 -0700731Volume *VolumeManager::lookupVolume(const char *label) {
732 VolumeCollection::iterator i;
733
734 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -0800735 if (label[0] == '/') {
736 if (!strcmp(label, (*i)->getMountpoint()))
737 return (*i);
738 } else {
739 if (!strcmp(label, (*i)->getLabel()))
740 return (*i);
741 }
San Mehat49e2bce2009-10-12 16:29:01 -0700742 }
743 return NULL;
744}
San Mehata19b2502010-01-06 10:33:53 -0800745
746bool VolumeManager::isMountpointMounted(const char *mp)
747{
748 char device[256];
749 char mount_path[256];
750 char rest[256];
751 FILE *fp;
752 char line[1024];
753
754 if (!(fp = fopen("/proc/mounts", "r"))) {
755 LOGE("Error opening /proc/mounts (%s)", strerror(errno));
756 return false;
757 }
758
759 while(fgets(line, sizeof(line), fp)) {
760 line[strlen(line)-1] = '\0';
761 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
762 if (!strcmp(mount_path, mp)) {
763 fclose(fp);
764 return true;
765 }
766
767 }
768
769 fclose(fp);
770 return false;
771}
772