blob: 8f1cb52692a430678e059e9dba7b7d593e95521f [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 Mehatfcf24fe2010-03-03 12:37:32 -080041#include "Asec.h"
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) {
San Mehata19b2502010-01-06 10:33:53 -0800165
San Mehat3bb60202010-02-19 18:14:36 -0800166 snprintf(buffer, maxlen, "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800167 return 0;
168}
169
San Mehat8b8f71b2010-01-11 09:17:25 -0800170int VolumeManager::createAsec(const char *id, unsigned int numSectors,
San Mehata19b2502010-01-06 10:33:53 -0800171 const char *fstype, const char *key, int ownerUid) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800172 struct asec_superblock sb;
173 memset(&sb, 0, sizeof(sb));
174
175 sb.magic = ASEC_SB_MAGIC;
176 sb.ver = ASEC_SB_VER;
San Mehata19b2502010-01-06 10:33:53 -0800177
San Mehatd31e3802010-02-18 08:37:45 -0800178 if (numSectors < ((1024*1024)/512)) {
179 LOGE("Invalid container size specified (%d sectors)", numSectors);
180 errno = EINVAL;
181 return -1;
182 }
183
San Mehata19b2502010-01-06 10:33:53 -0800184 if (lookupVolume(id)) {
San Mehat3bb60202010-02-19 18:14:36 -0800185 LOGE("ASEC id '%s' currently exists", id);
San Mehata19b2502010-01-06 10:33:53 -0800186 errno = EADDRINUSE;
187 return -1;
188 }
189
190 char asecFileName[255];
San Mehat3bb60202010-02-19 18:14:36 -0800191 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800192
193 if (!access(asecFileName, F_OK)) {
194 LOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
195 asecFileName, strerror(errno));
196 errno = EADDRINUSE;
197 return -1;
198 }
199
San Mehatfcf24fe2010-03-03 12:37:32 -0800200 /*
201 * Add some headroom
202 */
203 unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
204 unsigned numImgSectors = numSectors + fatSize + 2;
205
206 if (numImgSectors % 63) {
207 numImgSectors += (63 - (numImgSectors % 63));
208 }
209
210 // Add +1 for our superblock which is at the end
211 if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
San Mehata19b2502010-01-06 10:33:53 -0800212 LOGE("ASEC image file creation failed (%s)", strerror(errno));
213 return -1;
214 }
215
216 char loopDevice[255];
San Mehat8da6bcb2010-01-09 12:24:05 -0800217 if (Loop::create(asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800218 LOGE("ASEC loop device creation failed (%s)", strerror(errno));
219 unlink(asecFileName);
220 return -1;
221 }
222
San Mehatb78a32c2010-01-10 13:02:12 -0800223 char dmDevice[255];
224 bool cleanupDm = false;
San Mehata19b2502010-01-06 10:33:53 -0800225
San Mehatb78a32c2010-01-10 13:02:12 -0800226 if (strcmp(key, "none")) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800227 // XXX: This is all we support for now
228 sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
229 if (Devmapper::create(id, loopDevice, key, numImgSectors, dmDevice,
San Mehatb78a32c2010-01-10 13:02:12 -0800230 sizeof(dmDevice))) {
231 LOGE("ASEC device mapping failed (%s)", strerror(errno));
232 Loop::destroyByDevice(loopDevice);
233 unlink(asecFileName);
234 return -1;
235 }
236 cleanupDm = true;
237 } else {
San Mehatfcf24fe2010-03-03 12:37:32 -0800238 sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
San Mehatb78a32c2010-01-10 13:02:12 -0800239 strcpy(dmDevice, loopDevice);
240 }
241
San Mehatfcf24fe2010-03-03 12:37:32 -0800242 /*
243 * Drop down the superblock at the end of the file
244 */
245
246 int sbfd = open(loopDevice, O_RDWR);
247 if (sbfd < 0) {
248 LOGE("Failed to open new DM device for superblock write (%s)", strerror(errno));
249 if (cleanupDm) {
250 Devmapper::destroy(id);
251 }
252 Loop::destroyByDevice(loopDevice);
253 unlink(asecFileName);
254 return -1;
255 }
256
257 if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
258 close(sbfd);
259 LOGE("Failed to lseek for superblock (%s)", strerror(errno));
260 if (cleanupDm) {
261 Devmapper::destroy(id);
262 }
263 Loop::destroyByDevice(loopDevice);
264 unlink(asecFileName);
265 return -1;
266 }
267
268 if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) {
269 close(sbfd);
270 LOGE("Failed to write superblock (%s)", strerror(errno));
271 if (cleanupDm) {
272 Devmapper::destroy(id);
273 }
274 Loop::destroyByDevice(loopDevice);
275 unlink(asecFileName);
276 return -1;
277 }
278 close(sbfd);
279
San Mehata1091cb2010-02-28 20:17:20 -0800280 if (strcmp(fstype, "none")) {
281 if (strcmp(fstype, "fat")) {
282 LOGW("Unknown fstype '%s' specified for container", fstype);
San Mehatb78a32c2010-01-10 13:02:12 -0800283 }
San Mehata19b2502010-01-06 10:33:53 -0800284
San Mehatfcf24fe2010-03-03 12:37:32 -0800285 if (Fat::format(dmDevice, numImgSectors)) {
San Mehata1091cb2010-02-28 20:17:20 -0800286 LOGE("ASEC FAT format failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800287 if (cleanupDm) {
288 Devmapper::destroy(id);
289 }
San Mehateb13a902010-01-07 12:12:50 -0800290 Loop::destroyByDevice(loopDevice);
291 unlink(asecFileName);
292 return -1;
293 }
San Mehata1091cb2010-02-28 20:17:20 -0800294 char mountPoint[255];
San Mehata19b2502010-01-06 10:33:53 -0800295
San Mehata1091cb2010-02-28 20:17:20 -0800296 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
297 if (mkdir(mountPoint, 0777)) {
298 if (errno != EEXIST) {
299 LOGE("Mountpoint creation failed (%s)", strerror(errno));
300 if (cleanupDm) {
301 Devmapper::destroy(id);
302 }
303 Loop::destroyByDevice(loopDevice);
304 unlink(asecFileName);
305 return -1;
306 }
San Mehatb78a32c2010-01-10 13:02:12 -0800307 }
San Mehata1091cb2010-02-28 20:17:20 -0800308
309 if (Fat::doMount(dmDevice, mountPoint, false, false, ownerUid,
310 0, 0000, false)) {
311 LOGE("ASEC FAT mount failed (%s)", strerror(errno));
312 if (cleanupDm) {
313 Devmapper::destroy(id);
314 }
315 Loop::destroyByDevice(loopDevice);
316 unlink(asecFileName);
317 return -1;
318 }
319 } else {
320 LOGI("Created raw secure container %s (no filesystem)", id);
San Mehata19b2502010-01-06 10:33:53 -0800321 }
San Mehat88705162010-01-15 09:26:28 -0800322
323 mActiveContainers->push_back(strdup(id));
San Mehata19b2502010-01-06 10:33:53 -0800324 return 0;
325}
326
327int VolumeManager::finalizeAsec(const char *id) {
328 char asecFileName[255];
329 char loopDevice[255];
330 char mountPoint[255];
331
San Mehat3bb60202010-02-19 18:14:36 -0800332 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800333
334 if (Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
335 LOGE("Unable to finalize %s (%s)", id, strerror(errno));
336 return -1;
337 }
338
San Mehat3bb60202010-02-19 18:14:36 -0800339 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatfff0b472010-01-06 19:19:46 -0800340 // XXX:
341 if (Fat::doMount(loopDevice, mountPoint, true, true, 0, 0, 0227, false)) {
San Mehata19b2502010-01-06 10:33:53 -0800342 LOGE("ASEC finalize mount failed (%s)", strerror(errno));
343 return -1;
344 }
345
346 LOGD("ASEC %s finalized", id);
347 return 0;
348}
349
San Mehat048b0802010-01-23 08:17:06 -0800350int VolumeManager::renameAsec(const char *id1, const char *id2) {
351 char *asecFilename1;
352 char *asecFilename2;
353 char mountPoint[255];
354
San Mehat3bb60202010-02-19 18:14:36 -0800355 asprintf(&asecFilename1, "%s/%s.asec", Volume::SEC_ASECDIR, id1);
356 asprintf(&asecFilename2, "%s/%s.asec", Volume::SEC_ASECDIR, id2);
San Mehat048b0802010-01-23 08:17:06 -0800357
San Mehat3bb60202010-02-19 18:14:36 -0800358 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
San Mehat048b0802010-01-23 08:17:06 -0800359 if (isMountpointMounted(mountPoint)) {
360 LOGW("Rename attempt when src mounted");
361 errno = EBUSY;
362 goto out_err;
363 }
364
San Mehat96956ed2010-02-24 08:42:51 -0800365 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2);
366 if (isMountpointMounted(mountPoint)) {
367 LOGW("Rename attempt when dst mounted");
368 errno = EBUSY;
369 goto out_err;
370 }
371
San Mehat048b0802010-01-23 08:17:06 -0800372 if (!access(asecFilename2, F_OK)) {
373 LOGE("Rename attempt when dst exists");
374 errno = EADDRINUSE;
375 goto out_err;
376 }
377
378 if (rename(asecFilename1, asecFilename2)) {
379 LOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
380 goto out_err;
381 }
382
383 free(asecFilename1);
384 free(asecFilename2);
385 return 0;
386
387out_err:
388 free(asecFilename1);
389 free(asecFilename2);
390 return -1;
391}
392
San Mehat4ba89482010-02-18 09:00:18 -0800393#define ASEC_UNMOUNT_RETRIES 5
394int VolumeManager::unmountAsec(const char *id, bool force) {
San Mehata19b2502010-01-06 10:33:53 -0800395 char asecFileName[255];
396 char mountPoint[255];
397
San Mehat3bb60202010-02-19 18:14:36 -0800398 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
399 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800400
San Mehat0586d542010-01-12 15:38:59 -0800401 if (!isMountpointMounted(mountPoint)) {
San Mehatb78a32c2010-01-10 13:02:12 -0800402 LOGE("Unmount request for ASEC %s when not mounted", id);
403 errno = EINVAL;
404 return -1;
405 }
San Mehat23969932010-01-09 07:08:06 -0800406
San Mehatb78a32c2010-01-10 13:02:12 -0800407 int i, rc;
San Mehat8c940ef2010-02-13 14:19:53 -0800408 for (i = 1; i <= ASEC_UNMOUNT_RETRIES; i++) {
San Mehatb78a32c2010-01-10 13:02:12 -0800409 rc = umount(mountPoint);
410 if (!rc) {
411 break;
San Mehata19b2502010-01-06 10:33:53 -0800412 }
San Mehatb78a32c2010-01-10 13:02:12 -0800413 if (rc && (errno == EINVAL || errno == ENOENT)) {
San Mehat12f4b892010-02-24 11:43:22 -0800414 LOGI("Secure container %s unmounted OK", id);
San Mehatb78a32c2010-01-10 13:02:12 -0800415 rc = 0;
416 break;
San Mehata19b2502010-01-06 10:33:53 -0800417 }
San Mehatb78a32c2010-01-10 13:02:12 -0800418 LOGW("ASEC %s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -0800419 id, i, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800420
San Mehat4ba89482010-02-18 09:00:18 -0800421 int action = 0; // default is to just complain
422
423 if (force) {
424 if (i > (ASEC_UNMOUNT_RETRIES - 2))
425 action = 2; // SIGKILL
426 else if (i > (ASEC_UNMOUNT_RETRIES - 3))
427 action = 1; // SIGHUP
428 }
San Mehat8c940ef2010-02-13 14:19:53 -0800429
San Mehat586536c2010-02-16 17:12:00 -0800430 Process::killProcessesWithOpenFiles(mountPoint, action);
San Mehat8c940ef2010-02-13 14:19:53 -0800431 usleep(1000 * 1000);
San Mehatb78a32c2010-01-10 13:02:12 -0800432 }
433
434 if (rc) {
San Mehat4ba89482010-02-18 09:00:18 -0800435 errno = EBUSY;
436 LOGE("Failed to unmount container %s (%s)", id, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800437 return -1;
438 }
439
San Mehat12f4b892010-02-24 11:43:22 -0800440 int retries = 10;
441
442 while(retries--) {
443 if (!rmdir(mountPoint)) {
444 break;
445 }
446
447 LOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
448 usleep(1000 * 1000);
449 }
450
451 if (!retries) {
452 LOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
San Mehatf5c61982010-02-03 11:04:46 -0800453 }
San Mehat88705162010-01-15 09:26:28 -0800454
San Mehatb78a32c2010-01-10 13:02:12 -0800455 if (Devmapper::destroy(id) && errno != ENXIO) {
456 LOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800457 }
458
459 char loopDevice[255];
460 if (!Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
461 Loop::destroyByDevice(loopDevice);
462 }
San Mehat88705162010-01-15 09:26:28 -0800463
464 AsecIdCollection::iterator it;
465 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
466 if (!strcmp(*it, id)) {
467 free(*it);
468 mActiveContainers->erase(it);
469 break;
470 }
471 }
472 if (it == mActiveContainers->end()) {
473 LOGW("mActiveContainers is inconsistent!");
474 }
San Mehatb78a32c2010-01-10 13:02:12 -0800475 return 0;
476}
477
San Mehat4ba89482010-02-18 09:00:18 -0800478int VolumeManager::destroyAsec(const char *id, bool force) {
San Mehatb78a32c2010-01-10 13:02:12 -0800479 char asecFileName[255];
480 char mountPoint[255];
481
San Mehat3bb60202010-02-19 18:14:36 -0800482 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehat55013f72010-02-24 12:12:34 -0800483 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatb78a32c2010-01-10 13:02:12 -0800484
San Mehat0586d542010-01-12 15:38:59 -0800485 if (isMountpointMounted(mountPoint)) {
San Mehat68f8ebd2010-01-23 07:21:21 -0800486 LOGD("Unmounting container before destroy");
San Mehat4ba89482010-02-18 09:00:18 -0800487 if (unmountAsec(id, force)) {
San Mehat0586d542010-01-12 15:38:59 -0800488 LOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
489 return -1;
490 }
491 }
San Mehata19b2502010-01-06 10:33:53 -0800492
San Mehat0586d542010-01-12 15:38:59 -0800493 if (unlink(asecFileName)) {
San Mehat68f8ebd2010-01-23 07:21:21 -0800494 LOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800495 return -1;
496 }
San Mehata19b2502010-01-06 10:33:53 -0800497
498 LOGD("ASEC %s destroyed", id);
499 return 0;
500}
501
502int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
503 char asecFileName[255];
504 char mountPoint[255];
505
San Mehat3bb60202010-02-19 18:14:36 -0800506 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
507 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800508
509 if (isMountpointMounted(mountPoint)) {
510 LOGE("ASEC %s already mounted", id);
511 errno = EBUSY;
512 return -1;
513 }
514
515 char loopDevice[255];
516 if (Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat8da6bcb2010-01-09 12:24:05 -0800517 if (Loop::create(asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800518 LOGE("ASEC loop device creation failed (%s)", strerror(errno));
519 return -1;
520 }
San Mehatb78a32c2010-01-10 13:02:12 -0800521 LOGD("New loop device created at %s", loopDevice);
522 } else {
523 LOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
524 }
525
526 char dmDevice[255];
527 bool cleanupDm = false;
San Mehatfcf24fe2010-03-03 12:37:32 -0800528 int fd;
529 unsigned int nr_sec = 0;
530
531 if ((fd = open(loopDevice, O_RDWR)) < 0) {
532 LOGE("Failed to open loopdevice (%s)", strerror(errno));
533 Loop::destroyByDevice(loopDevice);
534 return -1;
535 }
536
537 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
538 LOGE("Failed to get loop size (%s)", strerror(errno));
539 Loop::destroyByDevice(loopDevice);
540 close(fd);
541 return -1;
542 }
543
544 /*
545 * Validate superblock
546 */
547 struct asec_superblock sb;
548 memset(&sb, 0, sizeof(sb));
549 if (lseek(fd, ((nr_sec-1) * 512), SEEK_SET) < 0) {
550 LOGE("lseek failed (%s)", strerror(errno));
551 close(fd);
552 Loop::destroyByDevice(loopDevice);
553 return -1;
554 }
555 if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) {
556 LOGE("superblock read failed (%s)", strerror(errno));
557 close(fd);
558 Loop::destroyByDevice(loopDevice);
559 return -1;
560 }
561
562 close(fd);
563
564 LOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
565 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
566 LOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
567 Loop::destroyByDevice(loopDevice);
568 errno = EMEDIUMTYPE;
569 return -1;
570 }
571 nr_sec--; // We don't want the devmapping to extend onto our superblock
572
San Mehatb78a32c2010-01-10 13:02:12 -0800573 if (strcmp(key, "none")) {
574 if (Devmapper::lookupActive(id, dmDevice, sizeof(dmDevice))) {
San Mehat8b8f71b2010-01-11 09:17:25 -0800575 if (Devmapper::create(id, loopDevice, key, nr_sec,
San Mehatb78a32c2010-01-10 13:02:12 -0800576 dmDevice, sizeof(dmDevice))) {
577 LOGE("ASEC device mapping failed (%s)", strerror(errno));
578 Loop::destroyByDevice(loopDevice);
579 return -1;
580 }
581 LOGD("New devmapper instance created at %s", dmDevice);
582 } else {
583 LOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
584 }
585 cleanupDm = true;
586 } else {
587 strcpy(dmDevice, loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800588 }
589
590 if (mkdir(mountPoint, 0777)) {
San Mehatb78a32c2010-01-10 13:02:12 -0800591 if (errno != EEXIST) {
592 LOGE("Mountpoint creation failed (%s)", strerror(errno));
593 if (cleanupDm) {
594 Devmapper::destroy(id);
595 }
596 Loop::destroyByDevice(loopDevice);
597 return -1;
598 }
San Mehata19b2502010-01-06 10:33:53 -0800599 }
600
San Mehatb78a32c2010-01-10 13:02:12 -0800601 if (Fat::doMount(dmDevice, mountPoint, true, false, ownerUid, 0,
San Mehatcff5ec32010-01-08 12:31:44 -0800602 0222, false)) {
603// 0227, false)) {
San Mehata19b2502010-01-06 10:33:53 -0800604 LOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800605 if (cleanupDm) {
606 Devmapper::destroy(id);
607 }
608 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800609 return -1;
610 }
611
San Mehat88705162010-01-15 09:26:28 -0800612 mActiveContainers->push_back(strdup(id));
San Mehata19b2502010-01-06 10:33:53 -0800613 LOGD("ASEC %s mounted", id);
614 return 0;
615}
616
San Mehat49e2bce2009-10-12 16:29:01 -0700617int VolumeManager::mountVolume(const char *label) {
618 Volume *v = lookupVolume(label);
619
620 if (!v) {
621 errno = ENOENT;
622 return -1;
623 }
624
San Mehata2677e42009-12-13 10:40:18 -0800625 return v->mountVol();
626}
627
628int VolumeManager::shareAvailable(const char *method, bool *avail) {
629
630 if (strcmp(method, "ums")) {
631 errno = ENOSYS;
632 return -1;
633 }
634
635 if (mUsbMassStorageConnected)
636 *avail = true;
637 else
638 *avail = false;
639 return 0;
640}
641
San Mehateba65e92010-01-29 05:15:16 -0800642int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
643 Volume *v = lookupVolume(label);
644
645 if (!v) {
646 errno = ENOENT;
647 return -1;
648 }
649
650 if (strcmp(method, "ums")) {
651 errno = ENOSYS;
652 return -1;
653 }
654
655 if (v->getState() != Volume::State_Shared) {
San Mehateba65e92010-01-29 05:15:16 -0800656 *enabled = false;
San Mehatb9aed742010-02-04 15:07:01 -0800657 } else {
658 *enabled = true;
San Mehateba65e92010-01-29 05:15:16 -0800659 }
660 return 0;
661}
662
San Mehata2677e42009-12-13 10:40:18 -0800663int VolumeManager::simulate(const char *cmd, const char *arg) {
664
665 if (!strcmp(cmd, "ums")) {
666 if (!strcmp(arg, "connect")) {
667 notifyUmsConnected(true);
668 } else if (!strcmp(arg, "disconnect")) {
669 notifyUmsConnected(false);
670 } else {
671 errno = EINVAL;
672 return -1;
673 }
674 } else {
675 errno = EINVAL;
676 return -1;
677 }
678 return 0;
679}
680
681int VolumeManager::shareVolume(const char *label, const char *method) {
682 Volume *v = lookupVolume(label);
683
684 if (!v) {
685 errno = ENOENT;
686 return -1;
687 }
688
689 /*
690 * Eventually, we'll want to support additional share back-ends,
691 * some of which may work while the media is mounted. For now,
692 * we just support UMS
693 */
694 if (strcmp(method, "ums")) {
695 errno = ENOSYS;
696 return -1;
697 }
698
699 if (v->getState() == Volume::State_NoMedia) {
700 errno = ENODEV;
701 return -1;
702 }
703
San Mehat49e2bce2009-10-12 16:29:01 -0700704 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -0800705 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -0700706 errno = EBUSY;
707 return -1;
708 }
709
San Mehata2677e42009-12-13 10:40:18 -0800710 dev_t d = v->getDiskDevice();
711 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
712 // This volume does not support raw disk access
713 errno = EINVAL;
714 return -1;
715 }
716
717 int fd;
718 char nodepath[255];
719 snprintf(nodepath,
720 sizeof(nodepath), "/dev/block/vold/%d:%d",
721 MAJOR(d), MINOR(d));
722
San Mehat0cde53c2009-12-22 08:32:33 -0800723 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file",
724 O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800725 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
726 return -1;
727 }
728
729 if (write(fd, nodepath, strlen(nodepath)) < 0) {
730 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
731 close(fd);
732 return -1;
733 }
734
735 close(fd);
736 v->handleVolumeShared();
737 return 0;
738}
739
740int VolumeManager::unshareVolume(const char *label, const char *method) {
741 Volume *v = lookupVolume(label);
742
743 if (!v) {
744 errno = ENOENT;
745 return -1;
746 }
747
748 if (strcmp(method, "ums")) {
749 errno = ENOSYS;
750 return -1;
751 }
752
753 if (v->getState() != Volume::State_Shared) {
754 errno = EINVAL;
755 return -1;
756 }
757
758 dev_t d = v->getDiskDevice();
759
760 int fd;
761 char nodepath[255];
762 snprintf(nodepath,
763 sizeof(nodepath), "/dev/block/vold/%d:%d",
764 MAJOR(d), MINOR(d));
765
San Mehat0cde53c2009-12-22 08:32:33 -0800766 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file", O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800767 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
768 return -1;
769 }
770
771 char ch = 0;
772 if (write(fd, &ch, 1) < 0) {
773 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
774 close(fd);
775 return -1;
776 }
777
778 close(fd);
779 v->handleVolumeUnshared();
780 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -0700781}
782
San Mehat4ba89482010-02-18 09:00:18 -0800783int VolumeManager::unmountVolume(const char *label, bool force) {
San Mehat49e2bce2009-10-12 16:29:01 -0700784 Volume *v = lookupVolume(label);
785
786 if (!v) {
787 errno = ENOENT;
788 return -1;
789 }
790
San Mehata2677e42009-12-13 10:40:18 -0800791 if (v->getState() == Volume::State_NoMedia) {
792 errno = ENODEV;
793 return -1;
794 }
795
San Mehat49e2bce2009-10-12 16:29:01 -0700796 if (v->getState() != Volume::State_Mounted) {
San Mehata2677e42009-12-13 10:40:18 -0800797 LOGW("Attempt to unmount volume which isn't mounted (%d)\n",
798 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -0700799 errno = EBUSY;
800 return -1;
801 }
802
San Mehat88705162010-01-15 09:26:28 -0800803 while(mActiveContainers->size()) {
804 AsecIdCollection::iterator it = mActiveContainers->begin();
805 LOGI("Unmounting ASEC %s (dependant on %s)", *it, v->getMountpoint());
San Mehat4ba89482010-02-18 09:00:18 -0800806 if (unmountAsec(*it, force)) {
San Mehat12f4b892010-02-24 11:43:22 -0800807 LOGE("Failed to unmount ASEC %s (%s)", *it, strerror(errno));
San Mehat0e382532010-02-24 08:25:55 -0800808 return -1;
San Mehat88705162010-01-15 09:26:28 -0800809 }
810 }
811
San Mehat4ba89482010-02-18 09:00:18 -0800812 return v->unmountVol(force);
San Mehat49e2bce2009-10-12 16:29:01 -0700813}
814
San Mehata2677e42009-12-13 10:40:18 -0800815/*
816 * Looks up a volume by it's label or mount-point
817 */
San Mehat49e2bce2009-10-12 16:29:01 -0700818Volume *VolumeManager::lookupVolume(const char *label) {
819 VolumeCollection::iterator i;
820
821 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -0800822 if (label[0] == '/') {
823 if (!strcmp(label, (*i)->getMountpoint()))
824 return (*i);
825 } else {
826 if (!strcmp(label, (*i)->getLabel()))
827 return (*i);
828 }
San Mehat49e2bce2009-10-12 16:29:01 -0700829 }
830 return NULL;
831}
San Mehata19b2502010-01-06 10:33:53 -0800832
833bool VolumeManager::isMountpointMounted(const char *mp)
834{
835 char device[256];
836 char mount_path[256];
837 char rest[256];
838 FILE *fp;
839 char line[1024];
840
841 if (!(fp = fopen("/proc/mounts", "r"))) {
842 LOGE("Error opening /proc/mounts (%s)", strerror(errno));
843 return false;
844 }
845
846 while(fgets(line, sizeof(line), fp)) {
847 line[strlen(line)-1] = '\0';
848 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
849 if (!strcmp(mount_path, mp)) {
850 fclose(fp);
851 return true;
852 }
853
854 }
855
856 fclose(fp);
857 return false;
858}
859