blob: 906fb9e37097da917f1c2dfccd4d8c6e39649192 [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
Kenny Root7b18a7b2010-03-15 13:13:41 -070030#include <openssl/md5.h>
31
San Mehatf1b736b2009-10-10 17:22:08 -070032#include <cutils/log.h>
33
San Mehatfd7f5872009-10-12 11:32:47 -070034#include <sysutils/NetlinkEvent.h>
35
San Mehatf1b736b2009-10-10 17:22:08 -070036#include "VolumeManager.h"
San Mehatae10b912009-10-12 14:57:05 -070037#include "DirectVolume.h"
San Mehata2677e42009-12-13 10:40:18 -080038#include "ResponseCode.h"
San Mehata19b2502010-01-06 10:33:53 -080039#include "Loop.h"
40#include "Fat.h"
San Mehatb78a32c2010-01-10 13:02:12 -080041#include "Devmapper.h"
San Mehat586536c2010-02-16 17:12:00 -080042#include "Process.h"
San Mehatfcf24fe2010-03-03 12:37:32 -080043#include "Asec.h"
San Mehat23969932010-01-09 07:08:06 -080044
San Mehatf1b736b2009-10-10 17:22:08 -070045VolumeManager *VolumeManager::sInstance = NULL;
46
47VolumeManager *VolumeManager::Instance() {
48 if (!sInstance)
49 sInstance = new VolumeManager();
50 return sInstance;
51}
52
53VolumeManager::VolumeManager() {
San Mehatd9a4e352010-03-12 13:32:47 -080054 mDebug = false;
San Mehatf1b736b2009-10-10 17:22:08 -070055 mVolumes = new VolumeCollection();
San Mehat88705162010-01-15 09:26:28 -080056 mActiveContainers = new AsecIdCollection();
San Mehatf1b736b2009-10-10 17:22:08 -070057 mBroadcaster = NULL;
Mike Lockwood99635f62010-06-25 23:04:04 -040058 mUsbMassStorageEnabled = false;
59 mUsbConnected = false;
Mike Lockwooda28056b2010-10-28 15:21:24 -040060 mUmsSharingCount = 0;
61 mSavedDirtyRatio = -1;
62 // set dirty ratio to 0 when UMS is active
63 mUmsDirtyRatio = 0;
Mike Lockwood99635f62010-06-25 23:04:04 -040064
65 readInitialState();
66}
67
68void VolumeManager::readInitialState() {
69 FILE *fp;
70 char state[255];
71
72 /*
73 * Read the initial mass storage enabled state
74 */
75 if ((fp = fopen("/sys/devices/virtual/usb_composite/usb_mass_storage/enable", "r"))) {
76 if (fgets(state, sizeof(state), fp)) {
77 mUsbMassStorageEnabled = !strncmp(state, "1", 1);
78 } else {
79 SLOGE("Failed to read usb_mass_storage enabled state (%s)", strerror(errno));
80 }
81 fclose(fp);
82 } else {
83 SLOGD("USB mass storage support is not enabled in the kernel");
84 }
85
86 /*
87 * Read the initial USB connected state
88 */
89 if ((fp = fopen("/sys/devices/virtual/switch/usb_configuration/state", "r"))) {
90 if (fgets(state, sizeof(state), fp)) {
91 mUsbConnected = !strncmp(state, "1", 1);
92 } else {
93 SLOGE("Failed to read usb_configuration switch (%s)", strerror(errno));
94 }
95 fclose(fp);
96 } else {
97 SLOGD("usb_configuration switch is not enabled in the kernel");
98 }
San Mehatf1b736b2009-10-10 17:22:08 -070099}
100
101VolumeManager::~VolumeManager() {
San Mehat88705162010-01-15 09:26:28 -0800102 delete mVolumes;
103 delete mActiveContainers;
San Mehatf1b736b2009-10-10 17:22:08 -0700104}
105
Kenny Root7b18a7b2010-03-15 13:13:41 -0700106char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700107 static const char* digits = "0123456789abcdef";
108
Kenny Root7b18a7b2010-03-15 13:13:41 -0700109 unsigned char sig[MD5_DIGEST_LENGTH];
110
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700111 if (buffer == NULL) {
112 SLOGE("Destination buffer is NULL");
113 errno = ESPIPE;
114 return NULL;
115 } else if (id == NULL) {
116 SLOGE("Source buffer is NULL");
117 errno = ESPIPE;
118 return NULL;
119 } else if (len < MD5_ASCII_LENGTH_PLUS_NULL) {
120 SLOGE("Target hash buffer size < %d bytes (%d)",
121 MD5_ASCII_LENGTH_PLUS_NULL, len);
San Mehatd9a4e352010-03-12 13:32:47 -0800122 errno = ESPIPE;
123 return NULL;
124 }
Kenny Root7b18a7b2010-03-15 13:13:41 -0700125
126 MD5(reinterpret_cast<const unsigned char*>(id), strlen(id), sig);
San Mehatd9a4e352010-03-12 13:32:47 -0800127
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700128 char *p = buffer;
Kenny Root7b18a7b2010-03-15 13:13:41 -0700129 for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700130 *p++ = digits[sig[i] >> 4];
131 *p++ = digits[sig[i] & 0x0F];
San Mehatd9a4e352010-03-12 13:32:47 -0800132 }
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700133 *p = '\0';
San Mehatd9a4e352010-03-12 13:32:47 -0800134
135 return buffer;
136}
137
138void VolumeManager::setDebug(bool enable) {
139 mDebug = enable;
140 VolumeCollection::iterator it;
141 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
142 (*it)->setDebug(enable);
143 }
144}
145
San Mehatf1b736b2009-10-10 17:22:08 -0700146int VolumeManager::start() {
147 return 0;
148}
149
150int VolumeManager::stop() {
151 return 0;
152}
153
154int VolumeManager::addVolume(Volume *v) {
155 mVolumes->push_back(v);
156 return 0;
157}
158
Mike Lockwood99635f62010-06-25 23:04:04 -0400159void VolumeManager::notifyUmsAvailable(bool available) {
San Mehata2677e42009-12-13 10:40:18 -0800160 char msg[255];
161
San Mehata2677e42009-12-13 10:40:18 -0800162 snprintf(msg, sizeof(msg), "Share method ums now %s",
Mike Lockwood99635f62010-06-25 23:04:04 -0400163 (available ? "available" : "unavailable"));
164 SLOGD(msg);
San Mehata2677e42009-12-13 10:40:18 -0800165 getBroadcaster()->sendBroadcast(ResponseCode::ShareAvailabilityChange,
166 msg, false);
167}
168
169void VolumeManager::handleSwitchEvent(NetlinkEvent *evt) {
San Mehat0cde53c2009-12-22 08:32:33 -0800170 const char *devpath = evt->findParam("DEVPATH");
San Mehata2677e42009-12-13 10:40:18 -0800171 const char *name = evt->findParam("SWITCH_NAME");
172 const char *state = evt->findParam("SWITCH_STATE");
173
San Mehat0cde53c2009-12-22 08:32:33 -0800174 if (!name || !state) {
San Mehat97ac40e2010-03-24 10:24:19 -0700175 SLOGW("Switch %s event missing name/state info", devpath);
San Mehat0cde53c2009-12-22 08:32:33 -0800176 return;
177 }
178
Mike Lockwood99635f62010-06-25 23:04:04 -0400179 bool oldAvailable = massStorageAvailable();
180 if (!strcmp(name, "usb_configuration")) {
181 mUsbConnected = !strcmp(state, "1");
182 SLOGD("USB %s", mUsbConnected ? "connected" : "disconnected");
183 bool newAvailable = massStorageAvailable();
184 if (newAvailable != oldAvailable) {
185 notifyUmsAvailable(newAvailable);
San Mehata2677e42009-12-13 10:40:18 -0800186 }
San Mehata2677e42009-12-13 10:40:18 -0800187 }
188}
Mike Lockwood99635f62010-06-25 23:04:04 -0400189void VolumeManager::handleUsbCompositeEvent(NetlinkEvent *evt) {
190 const char *function = evt->findParam("FUNCTION");
191 const char *enabled = evt->findParam("ENABLED");
192
193 if (!function || !enabled) {
194 SLOGW("usb_composite event missing function/enabled info");
195 return;
196 }
197
198 if (!strcmp(function, "usb_mass_storage")) {
199 bool oldAvailable = massStorageAvailable();
200 mUsbMassStorageEnabled = !strcmp(enabled, "1");
201 SLOGD("usb_mass_storage function %s", mUsbMassStorageEnabled ? "enabled" : "disabled");
202 bool newAvailable = massStorageAvailable();
203 if (newAvailable != oldAvailable) {
204 notifyUmsAvailable(newAvailable);
205 }
206 }
207}
San Mehata2677e42009-12-13 10:40:18 -0800208
San Mehatfd7f5872009-10-12 11:32:47 -0700209void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
210 const char *devpath = evt->findParam("DEVPATH");
San Mehatf1b736b2009-10-10 17:22:08 -0700211
San Mehatfd7f5872009-10-12 11:32:47 -0700212 /* Lookup a volume to handle this device */
San Mehatf1b736b2009-10-10 17:22:08 -0700213 VolumeCollection::iterator it;
214 bool hit = false;
215 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
San Mehatfd7f5872009-10-12 11:32:47 -0700216 if (!(*it)->handleBlockEvent(evt)) {
San Mehata2677e42009-12-13 10:40:18 -0800217#ifdef NETLINK_DEBUG
San Mehat97ac40e2010-03-24 10:24:19 -0700218 SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
San Mehata2677e42009-12-13 10:40:18 -0800219#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700220 hit = true;
San Mehatf1b736b2009-10-10 17:22:08 -0700221 break;
222 }
223 }
224
225 if (!hit) {
San Mehata2677e42009-12-13 10:40:18 -0800226#ifdef NETLINK_DEBUG
San Mehat97ac40e2010-03-24 10:24:19 -0700227 SLOGW("No volumes handled block event for '%s'", devpath);
San Mehata2677e42009-12-13 10:40:18 -0800228#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700229 }
230}
231
San Mehatf1b736b2009-10-10 17:22:08 -0700232int VolumeManager::listVolumes(SocketClient *cli) {
233 VolumeCollection::iterator i;
234
235 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
236 char *buffer;
237 asprintf(&buffer, "%s %s %d",
238 (*i)->getLabel(), (*i)->getMountpoint(),
239 (*i)->getState());
San Mehata2677e42009-12-13 10:40:18 -0800240 cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
San Mehatf1b736b2009-10-10 17:22:08 -0700241 free(buffer);
242 }
San Mehata2677e42009-12-13 10:40:18 -0800243 cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
San Mehatf1b736b2009-10-10 17:22:08 -0700244 return 0;
245}
San Mehat49e2bce2009-10-12 16:29:01 -0700246
San Mehata2677e42009-12-13 10:40:18 -0800247int VolumeManager::formatVolume(const char *label) {
248 Volume *v = lookupVolume(label);
249
250 if (!v) {
251 errno = ENOENT;
252 return -1;
253 }
254
255 return v->formatVol();
256}
257
Kenny Root508c0e12010-07-12 09:59:49 -0700258int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) {
259 char idHash[33];
260 if (!asecHash(sourceFile, idHash, sizeof(idHash))) {
261 SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno));
262 return -1;
263 }
264
265 memset(mountPath, 0, mountPathLen);
266 snprintf(mountPath, mountPathLen, "%s/%s", Volume::LOOPDIR, idHash);
267
268 if (access(mountPath, F_OK)) {
269 errno = ENOENT;
270 return -1;
271 }
272
273 return 0;
274}
275
San Mehata19b2502010-01-06 10:33:53 -0800276int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
San Mehat88ac2c02010-03-23 11:15:58 -0700277 char asecFileName[255];
278 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
279
280 memset(buffer, 0, maxlen);
281 if (access(asecFileName, F_OK)) {
282 errno = ENOENT;
283 return -1;
284 }
San Mehata19b2502010-01-06 10:33:53 -0800285
San Mehat3bb60202010-02-19 18:14:36 -0800286 snprintf(buffer, maxlen, "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800287 return 0;
288}
289
San Mehat8b8f71b2010-01-11 09:17:25 -0800290int VolumeManager::createAsec(const char *id, unsigned int numSectors,
San Mehata19b2502010-01-06 10:33:53 -0800291 const char *fstype, const char *key, int ownerUid) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800292 struct asec_superblock sb;
293 memset(&sb, 0, sizeof(sb));
294
295 sb.magic = ASEC_SB_MAGIC;
296 sb.ver = ASEC_SB_VER;
San Mehata19b2502010-01-06 10:33:53 -0800297
San Mehatd31e3802010-02-18 08:37:45 -0800298 if (numSectors < ((1024*1024)/512)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700299 SLOGE("Invalid container size specified (%d sectors)", numSectors);
San Mehatd31e3802010-02-18 08:37:45 -0800300 errno = EINVAL;
301 return -1;
302 }
303
San Mehata19b2502010-01-06 10:33:53 -0800304 if (lookupVolume(id)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700305 SLOGE("ASEC id '%s' currently exists", id);
San Mehata19b2502010-01-06 10:33:53 -0800306 errno = EADDRINUSE;
307 return -1;
308 }
309
310 char asecFileName[255];
San Mehat3bb60202010-02-19 18:14:36 -0800311 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800312
313 if (!access(asecFileName, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700314 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
San Mehata19b2502010-01-06 10:33:53 -0800315 asecFileName, strerror(errno));
316 errno = EADDRINUSE;
317 return -1;
318 }
319
San Mehatfcf24fe2010-03-03 12:37:32 -0800320 /*
321 * Add some headroom
322 */
323 unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
324 unsigned numImgSectors = numSectors + fatSize + 2;
325
326 if (numImgSectors % 63) {
327 numImgSectors += (63 - (numImgSectors % 63));
328 }
329
330 // Add +1 for our superblock which is at the end
331 if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700332 SLOGE("ASEC image file creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800333 return -1;
334 }
335
San Mehatd9a4e352010-03-12 13:32:47 -0800336 char idHash[33];
337 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700338 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800339 unlink(asecFileName);
340 return -1;
341 }
342
San Mehata19b2502010-01-06 10:33:53 -0800343 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800344 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700345 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800346 unlink(asecFileName);
347 return -1;
348 }
349
San Mehatb78a32c2010-01-10 13:02:12 -0800350 char dmDevice[255];
351 bool cleanupDm = false;
San Mehata19b2502010-01-06 10:33:53 -0800352
San Mehatb78a32c2010-01-10 13:02:12 -0800353 if (strcmp(key, "none")) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800354 // XXX: This is all we support for now
355 sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
San Mehatd9a4e352010-03-12 13:32:47 -0800356 if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
San Mehatb78a32c2010-01-10 13:02:12 -0800357 sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700358 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800359 Loop::destroyByDevice(loopDevice);
360 unlink(asecFileName);
361 return -1;
362 }
363 cleanupDm = true;
364 } else {
San Mehatfcf24fe2010-03-03 12:37:32 -0800365 sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
San Mehatb78a32c2010-01-10 13:02:12 -0800366 strcpy(dmDevice, loopDevice);
367 }
368
San Mehatfcf24fe2010-03-03 12:37:32 -0800369 /*
370 * Drop down the superblock at the end of the file
371 */
372
373 int sbfd = open(loopDevice, O_RDWR);
374 if (sbfd < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700375 SLOGE("Failed to open new DM device for superblock write (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800376 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800377 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800378 }
379 Loop::destroyByDevice(loopDevice);
380 unlink(asecFileName);
381 return -1;
382 }
383
384 if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
385 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700386 SLOGE("Failed to lseek for superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800387 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800388 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800389 }
390 Loop::destroyByDevice(loopDevice);
391 unlink(asecFileName);
392 return -1;
393 }
394
395 if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) {
396 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700397 SLOGE("Failed to write superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800398 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800399 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800400 }
401 Loop::destroyByDevice(loopDevice);
402 unlink(asecFileName);
403 return -1;
404 }
405 close(sbfd);
406
San Mehata1091cb2010-02-28 20:17:20 -0800407 if (strcmp(fstype, "none")) {
408 if (strcmp(fstype, "fat")) {
San Mehat97ac40e2010-03-24 10:24:19 -0700409 SLOGW("Unknown fstype '%s' specified for container", fstype);
San Mehatb78a32c2010-01-10 13:02:12 -0800410 }
San Mehata19b2502010-01-06 10:33:53 -0800411
San Mehatfcf24fe2010-03-03 12:37:32 -0800412 if (Fat::format(dmDevice, numImgSectors)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700413 SLOGE("ASEC FAT format failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800414 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800415 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800416 }
San Mehateb13a902010-01-07 12:12:50 -0800417 Loop::destroyByDevice(loopDevice);
418 unlink(asecFileName);
419 return -1;
420 }
San Mehata1091cb2010-02-28 20:17:20 -0800421 char mountPoint[255];
San Mehata19b2502010-01-06 10:33:53 -0800422
San Mehata1091cb2010-02-28 20:17:20 -0800423 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
424 if (mkdir(mountPoint, 0777)) {
425 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -0700426 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800427 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800428 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800429 }
430 Loop::destroyByDevice(loopDevice);
431 unlink(asecFileName);
432 return -1;
433 }
San Mehatb78a32c2010-01-10 13:02:12 -0800434 }
San Mehata1091cb2010-02-28 20:17:20 -0800435
Kenny Roota3e06082010-08-27 08:31:35 -0700436 if (Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid,
San Mehata1091cb2010-02-28 20:17:20 -0800437 0, 0000, false)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700438 SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800439 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800440 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800441 }
442 Loop::destroyByDevice(loopDevice);
443 unlink(asecFileName);
444 return -1;
445 }
446 } else {
San Mehat97ac40e2010-03-24 10:24:19 -0700447 SLOGI("Created raw secure container %s (no filesystem)", id);
San Mehata19b2502010-01-06 10:33:53 -0800448 }
San Mehat88705162010-01-15 09:26:28 -0800449
Kenny Rootcbacf782010-09-24 15:11:48 -0700450 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehata19b2502010-01-06 10:33:53 -0800451 return 0;
452}
453
454int VolumeManager::finalizeAsec(const char *id) {
455 char asecFileName[255];
456 char loopDevice[255];
457 char mountPoint[255];
458
San Mehat3bb60202010-02-19 18:14:36 -0800459 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800460
San Mehatd9a4e352010-03-12 13:32:47 -0800461 char idHash[33];
462 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700463 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800464 return -1;
465 }
466
467 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700468 SLOGE("Unable to finalize %s (%s)", id, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800469 return -1;
470 }
471
San Mehat3bb60202010-02-19 18:14:36 -0800472 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatfff0b472010-01-06 19:19:46 -0800473 // XXX:
Kenny Roota3e06082010-08-27 08:31:35 -0700474 if (Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700475 SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800476 return -1;
477 }
478
San Mehatd9a4e352010-03-12 13:32:47 -0800479 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700480 SLOGD("ASEC %s finalized", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800481 }
San Mehata19b2502010-01-06 10:33:53 -0800482 return 0;
483}
484
San Mehat048b0802010-01-23 08:17:06 -0800485int VolumeManager::renameAsec(const char *id1, const char *id2) {
486 char *asecFilename1;
487 char *asecFilename2;
488 char mountPoint[255];
489
San Mehat3bb60202010-02-19 18:14:36 -0800490 asprintf(&asecFilename1, "%s/%s.asec", Volume::SEC_ASECDIR, id1);
491 asprintf(&asecFilename2, "%s/%s.asec", Volume::SEC_ASECDIR, id2);
San Mehat048b0802010-01-23 08:17:06 -0800492
San Mehat3bb60202010-02-19 18:14:36 -0800493 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
San Mehat048b0802010-01-23 08:17:06 -0800494 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700495 SLOGW("Rename attempt when src mounted");
San Mehat048b0802010-01-23 08:17:06 -0800496 errno = EBUSY;
497 goto out_err;
498 }
499
San Mehat96956ed2010-02-24 08:42:51 -0800500 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2);
501 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700502 SLOGW("Rename attempt when dst mounted");
San Mehat96956ed2010-02-24 08:42:51 -0800503 errno = EBUSY;
504 goto out_err;
505 }
506
San Mehat048b0802010-01-23 08:17:06 -0800507 if (!access(asecFilename2, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700508 SLOGE("Rename attempt when dst exists");
San Mehat048b0802010-01-23 08:17:06 -0800509 errno = EADDRINUSE;
510 goto out_err;
511 }
512
513 if (rename(asecFilename1, asecFilename2)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700514 SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
San Mehat048b0802010-01-23 08:17:06 -0800515 goto out_err;
516 }
517
518 free(asecFilename1);
519 free(asecFilename2);
520 return 0;
521
522out_err:
523 free(asecFilename1);
524 free(asecFilename2);
525 return -1;
526}
527
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700528#define UNMOUNT_RETRIES 5
529#define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
San Mehat4ba89482010-02-18 09:00:18 -0800530int VolumeManager::unmountAsec(const char *id, bool force) {
San Mehata19b2502010-01-06 10:33:53 -0800531 char asecFileName[255];
532 char mountPoint[255];
533
San Mehat3bb60202010-02-19 18:14:36 -0800534 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
535 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800536
San Mehatd9a4e352010-03-12 13:32:47 -0800537 char idHash[33];
538 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700539 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800540 return -1;
541 }
542
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700543 return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
544}
545
Kenny Root508c0e12010-07-12 09:59:49 -0700546int VolumeManager::unmountObb(const char *fileName, bool force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700547 char mountPoint[255];
548
549 char idHash[33];
550 if (!asecHash(fileName, idHash, sizeof(idHash))) {
551 SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
552 return -1;
553 }
554
555 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
556
557 return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
558}
559
560int VolumeManager::unmountLoopImage(const char *id, const char *idHash,
561 const char *fileName, const char *mountPoint, bool force) {
San Mehat0586d542010-01-12 15:38:59 -0800562 if (!isMountpointMounted(mountPoint)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700563 SLOGE("Unmount request for %s when not mounted", id);
Kenny Root918e5f92010-09-30 18:00:52 -0700564 errno = ENOENT;
San Mehatb78a32c2010-01-10 13:02:12 -0800565 return -1;
566 }
San Mehat23969932010-01-09 07:08:06 -0800567
San Mehatb78a32c2010-01-10 13:02:12 -0800568 int i, rc;
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700569 for (i = 1; i <= UNMOUNT_RETRIES; i++) {
San Mehatb78a32c2010-01-10 13:02:12 -0800570 rc = umount(mountPoint);
571 if (!rc) {
572 break;
San Mehata19b2502010-01-06 10:33:53 -0800573 }
San Mehatb78a32c2010-01-10 13:02:12 -0800574 if (rc && (errno == EINVAL || errno == ENOENT)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700575 SLOGI("Container %s unmounted OK", id);
San Mehatb78a32c2010-01-10 13:02:12 -0800576 rc = 0;
577 break;
San Mehata19b2502010-01-06 10:33:53 -0800578 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700579 SLOGW("%s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -0800580 id, i, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800581
San Mehat4ba89482010-02-18 09:00:18 -0800582 int action = 0; // default is to just complain
583
584 if (force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700585 if (i > (UNMOUNT_RETRIES - 2))
San Mehat4ba89482010-02-18 09:00:18 -0800586 action = 2; // SIGKILL
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700587 else if (i > (UNMOUNT_RETRIES - 3))
San Mehat4ba89482010-02-18 09:00:18 -0800588 action = 1; // SIGHUP
589 }
San Mehat8c940ef2010-02-13 14:19:53 -0800590
San Mehat586536c2010-02-16 17:12:00 -0800591 Process::killProcessesWithOpenFiles(mountPoint, action);
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700592 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehatb78a32c2010-01-10 13:02:12 -0800593 }
594
595 if (rc) {
San Mehat4ba89482010-02-18 09:00:18 -0800596 errno = EBUSY;
San Mehat97ac40e2010-03-24 10:24:19 -0700597 SLOGE("Failed to unmount container %s (%s)", id, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800598 return -1;
599 }
600
San Mehat12f4b892010-02-24 11:43:22 -0800601 int retries = 10;
602
603 while(retries--) {
604 if (!rmdir(mountPoint)) {
605 break;
606 }
607
San Mehat97ac40e2010-03-24 10:24:19 -0700608 SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700609 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehat12f4b892010-02-24 11:43:22 -0800610 }
611
612 if (!retries) {
San Mehat97ac40e2010-03-24 10:24:19 -0700613 SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
San Mehatf5c61982010-02-03 11:04:46 -0800614 }
San Mehat88705162010-01-15 09:26:28 -0800615
San Mehatd9a4e352010-03-12 13:32:47 -0800616 if (Devmapper::destroy(idHash) && errno != ENXIO) {
San Mehat97ac40e2010-03-24 10:24:19 -0700617 SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800618 }
619
620 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800621 if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800622 Loop::destroyByDevice(loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800623 } else {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700624 SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800625 }
San Mehat88705162010-01-15 09:26:28 -0800626
627 AsecIdCollection::iterator it;
628 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
Kenny Rootcbacf782010-09-24 15:11:48 -0700629 ContainerData* cd = *it;
630 if (!strcmp(cd->id, id)) {
San Mehat88705162010-01-15 09:26:28 -0800631 free(*it);
632 mActiveContainers->erase(it);
633 break;
634 }
635 }
636 if (it == mActiveContainers->end()) {
San Mehat97ac40e2010-03-24 10:24:19 -0700637 SLOGW("mActiveContainers is inconsistent!");
San Mehat88705162010-01-15 09:26:28 -0800638 }
San Mehatb78a32c2010-01-10 13:02:12 -0800639 return 0;
640}
641
San Mehat4ba89482010-02-18 09:00:18 -0800642int VolumeManager::destroyAsec(const char *id, bool force) {
San Mehatb78a32c2010-01-10 13:02:12 -0800643 char asecFileName[255];
644 char mountPoint[255];
645
San Mehat3bb60202010-02-19 18:14:36 -0800646 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehat55013f72010-02-24 12:12:34 -0800647 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatb78a32c2010-01-10 13:02:12 -0800648
San Mehat0586d542010-01-12 15:38:59 -0800649 if (isMountpointMounted(mountPoint)) {
San Mehatd9a4e352010-03-12 13:32:47 -0800650 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700651 SLOGD("Unmounting container before destroy");
San Mehatd9a4e352010-03-12 13:32:47 -0800652 }
San Mehat4ba89482010-02-18 09:00:18 -0800653 if (unmountAsec(id, force)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700654 SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800655 return -1;
656 }
657 }
San Mehata19b2502010-01-06 10:33:53 -0800658
San Mehat0586d542010-01-12 15:38:59 -0800659 if (unlink(asecFileName)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700660 SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800661 return -1;
662 }
San Mehata19b2502010-01-06 10:33:53 -0800663
San Mehatd9a4e352010-03-12 13:32:47 -0800664 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700665 SLOGD("ASEC %s destroyed", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800666 }
San Mehata19b2502010-01-06 10:33:53 -0800667 return 0;
668}
669
670int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
671 char asecFileName[255];
672 char mountPoint[255];
673
San Mehat3bb60202010-02-19 18:14:36 -0800674 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
675 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800676
677 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700678 SLOGE("ASEC %s already mounted", id);
San Mehata19b2502010-01-06 10:33:53 -0800679 errno = EBUSY;
680 return -1;
681 }
682
San Mehatd9a4e352010-03-12 13:32:47 -0800683 char idHash[33];
684 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700685 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800686 return -1;
687 }
Kenny Root7b18a7b2010-03-15 13:13:41 -0700688
San Mehata19b2502010-01-06 10:33:53 -0800689 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800690 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
691 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700692 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800693 return -1;
694 }
San Mehatd9a4e352010-03-12 13:32:47 -0800695 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700696 SLOGD("New loop device created at %s", loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800697 }
San Mehatb78a32c2010-01-10 13:02:12 -0800698 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800699 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700700 SLOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800701 }
San Mehatb78a32c2010-01-10 13:02:12 -0800702 }
703
704 char dmDevice[255];
705 bool cleanupDm = false;
San Mehatfcf24fe2010-03-03 12:37:32 -0800706 int fd;
707 unsigned int nr_sec = 0;
708
709 if ((fd = open(loopDevice, O_RDWR)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700710 SLOGE("Failed to open loopdevice (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800711 Loop::destroyByDevice(loopDevice);
712 return -1;
713 }
714
715 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700716 SLOGE("Failed to get loop size (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800717 Loop::destroyByDevice(loopDevice);
718 close(fd);
719 return -1;
720 }
721
722 /*
723 * Validate superblock
724 */
725 struct asec_superblock sb;
726 memset(&sb, 0, sizeof(sb));
727 if (lseek(fd, ((nr_sec-1) * 512), SEEK_SET) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700728 SLOGE("lseek failed (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800729 close(fd);
730 Loop::destroyByDevice(loopDevice);
731 return -1;
732 }
733 if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700734 SLOGE("superblock read failed (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800735 close(fd);
736 Loop::destroyByDevice(loopDevice);
737 return -1;
738 }
739
740 close(fd);
741
San Mehatd9a4e352010-03-12 13:32:47 -0800742 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700743 SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatd9a4e352010-03-12 13:32:47 -0800744 }
San Mehatfcf24fe2010-03-03 12:37:32 -0800745 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
San Mehat97ac40e2010-03-24 10:24:19 -0700746 SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatfcf24fe2010-03-03 12:37:32 -0800747 Loop::destroyByDevice(loopDevice);
748 errno = EMEDIUMTYPE;
749 return -1;
750 }
751 nr_sec--; // We don't want the devmapping to extend onto our superblock
752
San Mehatb78a32c2010-01-10 13:02:12 -0800753 if (strcmp(key, "none")) {
San Mehatd9a4e352010-03-12 13:32:47 -0800754 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
755 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
San Mehatb78a32c2010-01-10 13:02:12 -0800756 dmDevice, sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700757 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800758 Loop::destroyByDevice(loopDevice);
759 return -1;
760 }
San Mehatd9a4e352010-03-12 13:32:47 -0800761 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700762 SLOGD("New devmapper instance created at %s", dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800763 }
San Mehatb78a32c2010-01-10 13:02:12 -0800764 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800765 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700766 SLOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800767 }
San Mehatb78a32c2010-01-10 13:02:12 -0800768 }
769 cleanupDm = true;
770 } else {
771 strcpy(dmDevice, loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800772 }
773
774 if (mkdir(mountPoint, 0777)) {
San Mehatb78a32c2010-01-10 13:02:12 -0800775 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -0700776 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800777 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800778 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800779 }
780 Loop::destroyByDevice(loopDevice);
781 return -1;
782 }
San Mehata19b2502010-01-06 10:33:53 -0800783 }
784
Kenny Roota3e06082010-08-27 08:31:35 -0700785 if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0,
San Mehatcff5ec32010-01-08 12:31:44 -0800786 0222, false)) {
787// 0227, false)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700788 SLOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800789 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800790 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800791 }
792 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800793 return -1;
794 }
795
Kenny Rootcbacf782010-09-24 15:11:48 -0700796 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehatd9a4e352010-03-12 13:32:47 -0800797 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700798 SLOGD("ASEC %s mounted", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800799 }
San Mehata19b2502010-01-06 10:33:53 -0800800 return 0;
801}
802
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700803/**
804 * Mounts an image file <code>img</code>.
805 */
Kenny Root508c0e12010-07-12 09:59:49 -0700806int VolumeManager::mountObb(const char *img, const char *key, int ownerUid) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700807 char mountPoint[255];
808
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700809 char idHash[33];
810 if (!asecHash(img, idHash, sizeof(idHash))) {
811 SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
812 return -1;
813 }
814
815 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
816
817 if (isMountpointMounted(mountPoint)) {
818 SLOGE("Image %s already mounted", img);
819 errno = EBUSY;
820 return -1;
821 }
822
823 char loopDevice[255];
824 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
825 if (Loop::create(idHash, img, loopDevice, sizeof(loopDevice))) {
826 SLOGE("Image loop device creation failed (%s)", strerror(errno));
827 return -1;
828 }
829 if (mDebug) {
830 SLOGD("New loop device created at %s", loopDevice);
831 }
832 } else {
833 if (mDebug) {
834 SLOGD("Found active loopback for %s at %s", img, loopDevice);
835 }
836 }
837
838 char dmDevice[255];
839 bool cleanupDm = false;
840 int fd;
841 unsigned int nr_sec = 0;
842
843 if ((fd = open(loopDevice, O_RDWR)) < 0) {
844 SLOGE("Failed to open loopdevice (%s)", strerror(errno));
845 Loop::destroyByDevice(loopDevice);
846 return -1;
847 }
848
849 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
850 SLOGE("Failed to get loop size (%s)", strerror(errno));
851 Loop::destroyByDevice(loopDevice);
852 close(fd);
853 return -1;
854 }
855
856 close(fd);
857
858 if (strcmp(key, "none")) {
859 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
860 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
861 dmDevice, sizeof(dmDevice))) {
862 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
863 Loop::destroyByDevice(loopDevice);
864 return -1;
865 }
866 if (mDebug) {
867 SLOGD("New devmapper instance created at %s", dmDevice);
868 }
869 } else {
870 if (mDebug) {
871 SLOGD("Found active devmapper for %s at %s", img, dmDevice);
872 }
873 }
874 cleanupDm = true;
875 } else {
876 strcpy(dmDevice, loopDevice);
877 }
878
879 if (mkdir(mountPoint, 0755)) {
880 if (errno != EEXIST) {
881 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
882 if (cleanupDm) {
883 Devmapper::destroy(idHash);
884 }
885 Loop::destroyByDevice(loopDevice);
886 return -1;
887 }
888 }
889
Kenny Roota3e06082010-08-27 08:31:35 -0700890 if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0,
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700891 0227, false)) {
892 SLOGE("Image mount failed (%s)", strerror(errno));
893 if (cleanupDm) {
894 Devmapper::destroy(idHash);
895 }
896 Loop::destroyByDevice(loopDevice);
897 return -1;
898 }
899
Kenny Rootcbacf782010-09-24 15:11:48 -0700900 mActiveContainers->push_back(new ContainerData(strdup(img), OBB));
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700901 if (mDebug) {
902 SLOGD("Image %s mounted", img);
903 }
904 return 0;
905}
906
San Mehat49e2bce2009-10-12 16:29:01 -0700907int VolumeManager::mountVolume(const char *label) {
908 Volume *v = lookupVolume(label);
909
910 if (!v) {
911 errno = ENOENT;
912 return -1;
913 }
914
San Mehata2677e42009-12-13 10:40:18 -0800915 return v->mountVol();
916}
917
Kenny Root508c0e12010-07-12 09:59:49 -0700918int VolumeManager::listMountedObbs(SocketClient* cli) {
919 char device[256];
920 char mount_path[256];
921 char rest[256];
922 FILE *fp;
923 char line[1024];
924
925 if (!(fp = fopen("/proc/mounts", "r"))) {
926 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
927 return -1;
928 }
929
930 // Create a string to compare against that has a trailing slash
931 int loopDirLen = sizeof(Volume::LOOPDIR);
932 char loopDir[loopDirLen + 2];
933 strcpy(loopDir, Volume::LOOPDIR);
934 loopDir[loopDirLen++] = '/';
935 loopDir[loopDirLen] = '\0';
936
937 while(fgets(line, sizeof(line), fp)) {
938 line[strlen(line)-1] = '\0';
939
940 /*
941 * Should look like:
942 * /dev/block/loop0 /mnt/obb/fc99df1323fd36424f864dcb76b76d65 ...
943 */
944 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
945
946 if (!strncmp(mount_path, loopDir, loopDirLen)) {
947 int fd = open(device, O_RDONLY);
948 if (fd >= 0) {
949 struct loop_info64 li;
950 if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
951 cli->sendMsg(ResponseCode::AsecListResult,
952 (const char*) li.lo_file_name, false);
953 }
954 close(fd);
955 }
956 }
957 }
958
959 fclose(fp);
960 return 0;
961}
962
San Mehata2677e42009-12-13 10:40:18 -0800963int VolumeManager::shareAvailable(const char *method, bool *avail) {
964
965 if (strcmp(method, "ums")) {
966 errno = ENOSYS;
967 return -1;
968 }
969
Mike Lockwood99635f62010-06-25 23:04:04 -0400970 *avail = massStorageAvailable();
San Mehata2677e42009-12-13 10:40:18 -0800971 return 0;
972}
973
San Mehateba65e92010-01-29 05:15:16 -0800974int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
975 Volume *v = lookupVolume(label);
976
977 if (!v) {
978 errno = ENOENT;
979 return -1;
980 }
981
982 if (strcmp(method, "ums")) {
983 errno = ENOSYS;
984 return -1;
985 }
986
987 if (v->getState() != Volume::State_Shared) {
San Mehateba65e92010-01-29 05:15:16 -0800988 *enabled = false;
San Mehatb9aed742010-02-04 15:07:01 -0800989 } else {
990 *enabled = true;
San Mehateba65e92010-01-29 05:15:16 -0800991 }
992 return 0;
993}
994
San Mehata2677e42009-12-13 10:40:18 -0800995int VolumeManager::simulate(const char *cmd, const char *arg) {
996
997 if (!strcmp(cmd, "ums")) {
998 if (!strcmp(arg, "connect")) {
Mike Lockwood99635f62010-06-25 23:04:04 -0400999 notifyUmsAvailable(true);
San Mehata2677e42009-12-13 10:40:18 -08001000 } else if (!strcmp(arg, "disconnect")) {
Mike Lockwood99635f62010-06-25 23:04:04 -04001001 notifyUmsAvailable(false);
San Mehata2677e42009-12-13 10:40:18 -08001002 } else {
1003 errno = EINVAL;
1004 return -1;
1005 }
1006 } else {
1007 errno = EINVAL;
1008 return -1;
1009 }
1010 return 0;
1011}
1012
1013int VolumeManager::shareVolume(const char *label, const char *method) {
1014 Volume *v = lookupVolume(label);
1015
1016 if (!v) {
1017 errno = ENOENT;
1018 return -1;
1019 }
1020
1021 /*
1022 * Eventually, we'll want to support additional share back-ends,
1023 * some of which may work while the media is mounted. For now,
1024 * we just support UMS
1025 */
1026 if (strcmp(method, "ums")) {
1027 errno = ENOSYS;
1028 return -1;
1029 }
1030
1031 if (v->getState() == Volume::State_NoMedia) {
1032 errno = ENODEV;
1033 return -1;
1034 }
1035
San Mehat49e2bce2009-10-12 16:29:01 -07001036 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -08001037 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -07001038 errno = EBUSY;
1039 return -1;
1040 }
1041
Mike Lockwood2dfe2972010-09-17 18:50:51 -04001042 dev_t d = v->getShareDevice();
San Mehata2677e42009-12-13 10:40:18 -08001043 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
1044 // This volume does not support raw disk access
1045 errno = EINVAL;
1046 return -1;
1047 }
1048
1049 int fd;
1050 char nodepath[255];
1051 snprintf(nodepath,
1052 sizeof(nodepath), "/dev/block/vold/%d:%d",
1053 MAJOR(d), MINOR(d));
1054
San Mehat0cde53c2009-12-22 08:32:33 -08001055 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file",
1056 O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001057 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001058 return -1;
1059 }
1060
1061 if (write(fd, nodepath, strlen(nodepath)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001062 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001063 close(fd);
1064 return -1;
1065 }
1066
1067 close(fd);
1068 v->handleVolumeShared();
Mike Lockwooda28056b2010-10-28 15:21:24 -04001069 if (mUmsSharingCount++ == 0) {
1070 FILE* fp;
1071 mSavedDirtyRatio = -1; // in case we fail
1072 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1073 char line[16];
1074 if (fgets(line, sizeof(line), fp) && sscanf(line, "%d", &mSavedDirtyRatio)) {
1075 fprintf(fp, "%d\n", mUmsDirtyRatio);
1076 } else {
1077 SLOGE("Failed to read dirty_ratio (%s)", strerror(errno));
1078 }
1079 fclose(fp);
1080 } else {
1081 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1082 }
1083 }
San Mehata2677e42009-12-13 10:40:18 -08001084 return 0;
1085}
1086
1087int VolumeManager::unshareVolume(const char *label, const char *method) {
1088 Volume *v = lookupVolume(label);
1089
1090 if (!v) {
1091 errno = ENOENT;
1092 return -1;
1093 }
1094
1095 if (strcmp(method, "ums")) {
1096 errno = ENOSYS;
1097 return -1;
1098 }
1099
1100 if (v->getState() != Volume::State_Shared) {
1101 errno = EINVAL;
1102 return -1;
1103 }
1104
San Mehata2677e42009-12-13 10:40:18 -08001105 int fd;
San Mehat0cde53c2009-12-22 08:32:33 -08001106 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file", O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001107 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001108 return -1;
1109 }
1110
1111 char ch = 0;
1112 if (write(fd, &ch, 1) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001113 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001114 close(fd);
1115 return -1;
1116 }
1117
1118 close(fd);
1119 v->handleVolumeUnshared();
Mike Lockwooda28056b2010-10-28 15:21:24 -04001120 if (--mUmsSharingCount == 0 && mSavedDirtyRatio != -1) {
1121 FILE* fp;
1122 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1123 fprintf(fp, "%d\n", mSavedDirtyRatio);
1124 fclose(fp);
1125 } else {
1126 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1127 }
1128 mSavedDirtyRatio = -1;
1129 }
San Mehata2677e42009-12-13 10:40:18 -08001130 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -07001131}
1132
San Mehat4ba89482010-02-18 09:00:18 -08001133int VolumeManager::unmountVolume(const char *label, bool force) {
San Mehat49e2bce2009-10-12 16:29:01 -07001134 Volume *v = lookupVolume(label);
1135
1136 if (!v) {
1137 errno = ENOENT;
1138 return -1;
1139 }
1140
San Mehata2677e42009-12-13 10:40:18 -08001141 if (v->getState() == Volume::State_NoMedia) {
1142 errno = ENODEV;
1143 return -1;
1144 }
1145
San Mehat49e2bce2009-10-12 16:29:01 -07001146 if (v->getState() != Volume::State_Mounted) {
San Mehat97ac40e2010-03-24 10:24:19 -07001147 SLOGW("Attempt to unmount volume which isn't mounted (%d)\n",
San Mehata2677e42009-12-13 10:40:18 -08001148 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -07001149 errno = EBUSY;
1150 return -1;
1151 }
1152
San Mehat1a06eda2010-04-15 12:58:50 -07001153 cleanupAsec(v, force);
San Mehat88705162010-01-15 09:26:28 -08001154
San Mehat4ba89482010-02-18 09:00:18 -08001155 return v->unmountVol(force);
San Mehat49e2bce2009-10-12 16:29:01 -07001156}
1157
San Mehata2677e42009-12-13 10:40:18 -08001158/*
1159 * Looks up a volume by it's label or mount-point
1160 */
San Mehat49e2bce2009-10-12 16:29:01 -07001161Volume *VolumeManager::lookupVolume(const char *label) {
1162 VolumeCollection::iterator i;
1163
1164 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -08001165 if (label[0] == '/') {
1166 if (!strcmp(label, (*i)->getMountpoint()))
1167 return (*i);
1168 } else {
1169 if (!strcmp(label, (*i)->getLabel()))
1170 return (*i);
1171 }
San Mehat49e2bce2009-10-12 16:29:01 -07001172 }
1173 return NULL;
1174}
San Mehata19b2502010-01-06 10:33:53 -08001175
1176bool VolumeManager::isMountpointMounted(const char *mp)
1177{
1178 char device[256];
1179 char mount_path[256];
1180 char rest[256];
1181 FILE *fp;
1182 char line[1024];
1183
1184 if (!(fp = fopen("/proc/mounts", "r"))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001185 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001186 return false;
1187 }
1188
1189 while(fgets(line, sizeof(line), fp)) {
1190 line[strlen(line)-1] = '\0';
1191 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1192 if (!strcmp(mount_path, mp)) {
1193 fclose(fp);
1194 return true;
1195 }
San Mehata19b2502010-01-06 10:33:53 -08001196 }
1197
1198 fclose(fp);
1199 return false;
1200}
1201
San Mehat1a06eda2010-04-15 12:58:50 -07001202int VolumeManager::cleanupAsec(Volume *v, bool force) {
1203 while(mActiveContainers->size()) {
1204 AsecIdCollection::iterator it = mActiveContainers->begin();
Kenny Rootcbacf782010-09-24 15:11:48 -07001205 ContainerData* cd = *it;
1206 SLOGI("Unmounting ASEC %s (dependant on %s)", cd->id, v->getMountpoint());
1207 if (cd->type == ASEC) {
1208 if (unmountAsec(cd->id, force)) {
1209 SLOGE("Failed to unmount ASEC %s (%s)", cd->id, strerror(errno));
1210 return -1;
1211 }
1212 } else if (cd->type == OBB) {
1213 if (unmountObb(cd->id, force)) {
1214 SLOGE("Failed to unmount OBB %s (%s)", cd->id, strerror(errno));
1215 return -1;
1216 }
1217 } else {
1218 SLOGE("Unknown container type %d!", cd->type);
San Mehat1a06eda2010-04-15 12:58:50 -07001219 return -1;
1220 }
1221 }
1222 return 0;
1223}
1224