blob: 32b567981413d981277754d3213105353cbcdc6e [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 }
187 } else {
San Mehat97ac40e2010-03-24 10:24:19 -0700188 SLOGW("Ignoring unknown switch '%s'", name);
San Mehata2677e42009-12-13 10:40:18 -0800189 }
190}
Mike Lockwood99635f62010-06-25 23:04:04 -0400191void VolumeManager::handleUsbCompositeEvent(NetlinkEvent *evt) {
192 const char *function = evt->findParam("FUNCTION");
193 const char *enabled = evt->findParam("ENABLED");
194
195 if (!function || !enabled) {
196 SLOGW("usb_composite event missing function/enabled info");
197 return;
198 }
199
200 if (!strcmp(function, "usb_mass_storage")) {
201 bool oldAvailable = massStorageAvailable();
202 mUsbMassStorageEnabled = !strcmp(enabled, "1");
203 SLOGD("usb_mass_storage function %s", mUsbMassStorageEnabled ? "enabled" : "disabled");
204 bool newAvailable = massStorageAvailable();
205 if (newAvailable != oldAvailable) {
206 notifyUmsAvailable(newAvailable);
207 }
208 }
209}
San Mehata2677e42009-12-13 10:40:18 -0800210
San Mehatfd7f5872009-10-12 11:32:47 -0700211void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
212 const char *devpath = evt->findParam("DEVPATH");
San Mehatf1b736b2009-10-10 17:22:08 -0700213
San Mehatfd7f5872009-10-12 11:32:47 -0700214 /* Lookup a volume to handle this device */
San Mehatf1b736b2009-10-10 17:22:08 -0700215 VolumeCollection::iterator it;
216 bool hit = false;
217 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
San Mehatfd7f5872009-10-12 11:32:47 -0700218 if (!(*it)->handleBlockEvent(evt)) {
San Mehata2677e42009-12-13 10:40:18 -0800219#ifdef NETLINK_DEBUG
San Mehat97ac40e2010-03-24 10:24:19 -0700220 SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
San Mehata2677e42009-12-13 10:40:18 -0800221#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700222 hit = true;
San Mehatf1b736b2009-10-10 17:22:08 -0700223 break;
224 }
225 }
226
227 if (!hit) {
San Mehata2677e42009-12-13 10:40:18 -0800228#ifdef NETLINK_DEBUG
San Mehat97ac40e2010-03-24 10:24:19 -0700229 SLOGW("No volumes handled block event for '%s'", devpath);
San Mehata2677e42009-12-13 10:40:18 -0800230#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700231 }
232}
233
San Mehatf1b736b2009-10-10 17:22:08 -0700234int VolumeManager::listVolumes(SocketClient *cli) {
235 VolumeCollection::iterator i;
236
237 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
238 char *buffer;
239 asprintf(&buffer, "%s %s %d",
240 (*i)->getLabel(), (*i)->getMountpoint(),
241 (*i)->getState());
San Mehata2677e42009-12-13 10:40:18 -0800242 cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
San Mehatf1b736b2009-10-10 17:22:08 -0700243 free(buffer);
244 }
San Mehata2677e42009-12-13 10:40:18 -0800245 cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
San Mehatf1b736b2009-10-10 17:22:08 -0700246 return 0;
247}
San Mehat49e2bce2009-10-12 16:29:01 -0700248
San Mehata2677e42009-12-13 10:40:18 -0800249int VolumeManager::formatVolume(const char *label) {
250 Volume *v = lookupVolume(label);
251
252 if (!v) {
253 errno = ENOENT;
254 return -1;
255 }
256
257 return v->formatVol();
258}
259
Kenny Root508c0e12010-07-12 09:59:49 -0700260int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) {
261 char idHash[33];
262 if (!asecHash(sourceFile, idHash, sizeof(idHash))) {
263 SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno));
264 return -1;
265 }
266
267 memset(mountPath, 0, mountPathLen);
268 snprintf(mountPath, mountPathLen, "%s/%s", Volume::LOOPDIR, idHash);
269
270 if (access(mountPath, F_OK)) {
271 errno = ENOENT;
272 return -1;
273 }
274
275 return 0;
276}
277
San Mehata19b2502010-01-06 10:33:53 -0800278int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
San Mehat88ac2c02010-03-23 11:15:58 -0700279 char asecFileName[255];
280 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
281
282 memset(buffer, 0, maxlen);
283 if (access(asecFileName, F_OK)) {
284 errno = ENOENT;
285 return -1;
286 }
San Mehata19b2502010-01-06 10:33:53 -0800287
San Mehat3bb60202010-02-19 18:14:36 -0800288 snprintf(buffer, maxlen, "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800289 return 0;
290}
291
San Mehat8b8f71b2010-01-11 09:17:25 -0800292int VolumeManager::createAsec(const char *id, unsigned int numSectors,
San Mehata19b2502010-01-06 10:33:53 -0800293 const char *fstype, const char *key, int ownerUid) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800294 struct asec_superblock sb;
295 memset(&sb, 0, sizeof(sb));
296
297 sb.magic = ASEC_SB_MAGIC;
298 sb.ver = ASEC_SB_VER;
San Mehata19b2502010-01-06 10:33:53 -0800299
San Mehatd31e3802010-02-18 08:37:45 -0800300 if (numSectors < ((1024*1024)/512)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700301 SLOGE("Invalid container size specified (%d sectors)", numSectors);
San Mehatd31e3802010-02-18 08:37:45 -0800302 errno = EINVAL;
303 return -1;
304 }
305
San Mehata19b2502010-01-06 10:33:53 -0800306 if (lookupVolume(id)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700307 SLOGE("ASEC id '%s' currently exists", id);
San Mehata19b2502010-01-06 10:33:53 -0800308 errno = EADDRINUSE;
309 return -1;
310 }
311
312 char asecFileName[255];
San Mehat3bb60202010-02-19 18:14:36 -0800313 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800314
315 if (!access(asecFileName, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700316 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
San Mehata19b2502010-01-06 10:33:53 -0800317 asecFileName, strerror(errno));
318 errno = EADDRINUSE;
319 return -1;
320 }
321
San Mehatfcf24fe2010-03-03 12:37:32 -0800322 /*
323 * Add some headroom
324 */
325 unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
326 unsigned numImgSectors = numSectors + fatSize + 2;
327
328 if (numImgSectors % 63) {
329 numImgSectors += (63 - (numImgSectors % 63));
330 }
331
332 // Add +1 for our superblock which is at the end
333 if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700334 SLOGE("ASEC image file creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800335 return -1;
336 }
337
San Mehatd9a4e352010-03-12 13:32:47 -0800338 char idHash[33];
339 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700340 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800341 unlink(asecFileName);
342 return -1;
343 }
344
San Mehata19b2502010-01-06 10:33:53 -0800345 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800346 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700347 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800348 unlink(asecFileName);
349 return -1;
350 }
351
San Mehatb78a32c2010-01-10 13:02:12 -0800352 char dmDevice[255];
353 bool cleanupDm = false;
San Mehata19b2502010-01-06 10:33:53 -0800354
San Mehatb78a32c2010-01-10 13:02:12 -0800355 if (strcmp(key, "none")) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800356 // XXX: This is all we support for now
357 sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
San Mehatd9a4e352010-03-12 13:32:47 -0800358 if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
San Mehatb78a32c2010-01-10 13:02:12 -0800359 sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700360 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800361 Loop::destroyByDevice(loopDevice);
362 unlink(asecFileName);
363 return -1;
364 }
365 cleanupDm = true;
366 } else {
San Mehatfcf24fe2010-03-03 12:37:32 -0800367 sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
San Mehatb78a32c2010-01-10 13:02:12 -0800368 strcpy(dmDevice, loopDevice);
369 }
370
San Mehatfcf24fe2010-03-03 12:37:32 -0800371 /*
372 * Drop down the superblock at the end of the file
373 */
374
375 int sbfd = open(loopDevice, O_RDWR);
376 if (sbfd < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700377 SLOGE("Failed to open new DM device for superblock write (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800378 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800379 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800380 }
381 Loop::destroyByDevice(loopDevice);
382 unlink(asecFileName);
383 return -1;
384 }
385
386 if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
387 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700388 SLOGE("Failed to lseek for superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800389 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800390 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800391 }
392 Loop::destroyByDevice(loopDevice);
393 unlink(asecFileName);
394 return -1;
395 }
396
397 if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) {
398 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700399 SLOGE("Failed to write superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800400 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800401 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800402 }
403 Loop::destroyByDevice(loopDevice);
404 unlink(asecFileName);
405 return -1;
406 }
407 close(sbfd);
408
San Mehata1091cb2010-02-28 20:17:20 -0800409 if (strcmp(fstype, "none")) {
410 if (strcmp(fstype, "fat")) {
San Mehat97ac40e2010-03-24 10:24:19 -0700411 SLOGW("Unknown fstype '%s' specified for container", fstype);
San Mehatb78a32c2010-01-10 13:02:12 -0800412 }
San Mehata19b2502010-01-06 10:33:53 -0800413
San Mehatfcf24fe2010-03-03 12:37:32 -0800414 if (Fat::format(dmDevice, numImgSectors)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700415 SLOGE("ASEC FAT format failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800416 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800417 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800418 }
San Mehateb13a902010-01-07 12:12:50 -0800419 Loop::destroyByDevice(loopDevice);
420 unlink(asecFileName);
421 return -1;
422 }
San Mehata1091cb2010-02-28 20:17:20 -0800423 char mountPoint[255];
San Mehata19b2502010-01-06 10:33:53 -0800424
San Mehata1091cb2010-02-28 20:17:20 -0800425 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
426 if (mkdir(mountPoint, 0777)) {
427 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -0700428 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800429 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800430 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800431 }
432 Loop::destroyByDevice(loopDevice);
433 unlink(asecFileName);
434 return -1;
435 }
San Mehatb78a32c2010-01-10 13:02:12 -0800436 }
San Mehata1091cb2010-02-28 20:17:20 -0800437
Kenny Roota3e06082010-08-27 08:31:35 -0700438 if (Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid,
San Mehata1091cb2010-02-28 20:17:20 -0800439 0, 0000, false)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700440 SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800441 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800442 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800443 }
444 Loop::destroyByDevice(loopDevice);
445 unlink(asecFileName);
446 return -1;
447 }
448 } else {
San Mehat97ac40e2010-03-24 10:24:19 -0700449 SLOGI("Created raw secure container %s (no filesystem)", id);
San Mehata19b2502010-01-06 10:33:53 -0800450 }
San Mehat88705162010-01-15 09:26:28 -0800451
Kenny Rootcbacf782010-09-24 15:11:48 -0700452 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehata19b2502010-01-06 10:33:53 -0800453 return 0;
454}
455
456int VolumeManager::finalizeAsec(const char *id) {
457 char asecFileName[255];
458 char loopDevice[255];
459 char mountPoint[255];
460
San Mehat3bb60202010-02-19 18:14:36 -0800461 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800462
San Mehatd9a4e352010-03-12 13:32:47 -0800463 char idHash[33];
464 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700465 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800466 return -1;
467 }
468
469 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700470 SLOGE("Unable to finalize %s (%s)", id, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800471 return -1;
472 }
473
San Mehat3bb60202010-02-19 18:14:36 -0800474 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatfff0b472010-01-06 19:19:46 -0800475 // XXX:
Kenny Roota3e06082010-08-27 08:31:35 -0700476 if (Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700477 SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800478 return -1;
479 }
480
San Mehatd9a4e352010-03-12 13:32:47 -0800481 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700482 SLOGD("ASEC %s finalized", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800483 }
San Mehata19b2502010-01-06 10:33:53 -0800484 return 0;
485}
486
San Mehat048b0802010-01-23 08:17:06 -0800487int VolumeManager::renameAsec(const char *id1, const char *id2) {
488 char *asecFilename1;
489 char *asecFilename2;
490 char mountPoint[255];
491
San Mehat3bb60202010-02-19 18:14:36 -0800492 asprintf(&asecFilename1, "%s/%s.asec", Volume::SEC_ASECDIR, id1);
493 asprintf(&asecFilename2, "%s/%s.asec", Volume::SEC_ASECDIR, id2);
San Mehat048b0802010-01-23 08:17:06 -0800494
San Mehat3bb60202010-02-19 18:14:36 -0800495 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
San Mehat048b0802010-01-23 08:17:06 -0800496 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700497 SLOGW("Rename attempt when src mounted");
San Mehat048b0802010-01-23 08:17:06 -0800498 errno = EBUSY;
499 goto out_err;
500 }
501
San Mehat96956ed2010-02-24 08:42:51 -0800502 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2);
503 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700504 SLOGW("Rename attempt when dst mounted");
San Mehat96956ed2010-02-24 08:42:51 -0800505 errno = EBUSY;
506 goto out_err;
507 }
508
San Mehat048b0802010-01-23 08:17:06 -0800509 if (!access(asecFilename2, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700510 SLOGE("Rename attempt when dst exists");
San Mehat048b0802010-01-23 08:17:06 -0800511 errno = EADDRINUSE;
512 goto out_err;
513 }
514
515 if (rename(asecFilename1, asecFilename2)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700516 SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
San Mehat048b0802010-01-23 08:17:06 -0800517 goto out_err;
518 }
519
520 free(asecFilename1);
521 free(asecFilename2);
522 return 0;
523
524out_err:
525 free(asecFilename1);
526 free(asecFilename2);
527 return -1;
528}
529
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700530#define UNMOUNT_RETRIES 5
531#define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
San Mehat4ba89482010-02-18 09:00:18 -0800532int VolumeManager::unmountAsec(const char *id, bool force) {
San Mehata19b2502010-01-06 10:33:53 -0800533 char asecFileName[255];
534 char mountPoint[255];
535
San Mehat3bb60202010-02-19 18:14:36 -0800536 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
537 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800538
San Mehatd9a4e352010-03-12 13:32:47 -0800539 char idHash[33];
540 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700541 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800542 return -1;
543 }
544
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700545 return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
546}
547
Kenny Root508c0e12010-07-12 09:59:49 -0700548int VolumeManager::unmountObb(const char *fileName, bool force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700549 char mountPoint[255];
550
551 char idHash[33];
552 if (!asecHash(fileName, idHash, sizeof(idHash))) {
553 SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
554 return -1;
555 }
556
557 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
558
559 return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
560}
561
562int VolumeManager::unmountLoopImage(const char *id, const char *idHash,
563 const char *fileName, const char *mountPoint, bool force) {
San Mehat0586d542010-01-12 15:38:59 -0800564 if (!isMountpointMounted(mountPoint)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700565 SLOGE("Unmount request for %s when not mounted", id);
Kenny Root918e5f92010-09-30 18:00:52 -0700566 errno = ENOENT;
San Mehatb78a32c2010-01-10 13:02:12 -0800567 return -1;
568 }
San Mehat23969932010-01-09 07:08:06 -0800569
San Mehatb78a32c2010-01-10 13:02:12 -0800570 int i, rc;
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700571 for (i = 1; i <= UNMOUNT_RETRIES; i++) {
San Mehatb78a32c2010-01-10 13:02:12 -0800572 rc = umount(mountPoint);
573 if (!rc) {
574 break;
San Mehata19b2502010-01-06 10:33:53 -0800575 }
San Mehatb78a32c2010-01-10 13:02:12 -0800576 if (rc && (errno == EINVAL || errno == ENOENT)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700577 SLOGI("Container %s unmounted OK", id);
San Mehatb78a32c2010-01-10 13:02:12 -0800578 rc = 0;
579 break;
San Mehata19b2502010-01-06 10:33:53 -0800580 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700581 SLOGW("%s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -0800582 id, i, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800583
San Mehat4ba89482010-02-18 09:00:18 -0800584 int action = 0; // default is to just complain
585
586 if (force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700587 if (i > (UNMOUNT_RETRIES - 2))
San Mehat4ba89482010-02-18 09:00:18 -0800588 action = 2; // SIGKILL
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700589 else if (i > (UNMOUNT_RETRIES - 3))
San Mehat4ba89482010-02-18 09:00:18 -0800590 action = 1; // SIGHUP
591 }
San Mehat8c940ef2010-02-13 14:19:53 -0800592
San Mehat586536c2010-02-16 17:12:00 -0800593 Process::killProcessesWithOpenFiles(mountPoint, action);
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700594 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehatb78a32c2010-01-10 13:02:12 -0800595 }
596
597 if (rc) {
San Mehat4ba89482010-02-18 09:00:18 -0800598 errno = EBUSY;
San Mehat97ac40e2010-03-24 10:24:19 -0700599 SLOGE("Failed to unmount container %s (%s)", id, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800600 return -1;
601 }
602
San Mehat12f4b892010-02-24 11:43:22 -0800603 int retries = 10;
604
605 while(retries--) {
606 if (!rmdir(mountPoint)) {
607 break;
608 }
609
San Mehat97ac40e2010-03-24 10:24:19 -0700610 SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700611 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehat12f4b892010-02-24 11:43:22 -0800612 }
613
614 if (!retries) {
San Mehat97ac40e2010-03-24 10:24:19 -0700615 SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
San Mehatf5c61982010-02-03 11:04:46 -0800616 }
San Mehat88705162010-01-15 09:26:28 -0800617
San Mehatd9a4e352010-03-12 13:32:47 -0800618 if (Devmapper::destroy(idHash) && errno != ENXIO) {
San Mehat97ac40e2010-03-24 10:24:19 -0700619 SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800620 }
621
622 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800623 if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800624 Loop::destroyByDevice(loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800625 } else {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700626 SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800627 }
San Mehat88705162010-01-15 09:26:28 -0800628
629 AsecIdCollection::iterator it;
630 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
Kenny Rootcbacf782010-09-24 15:11:48 -0700631 ContainerData* cd = *it;
632 if (!strcmp(cd->id, id)) {
San Mehat88705162010-01-15 09:26:28 -0800633 free(*it);
634 mActiveContainers->erase(it);
635 break;
636 }
637 }
638 if (it == mActiveContainers->end()) {
San Mehat97ac40e2010-03-24 10:24:19 -0700639 SLOGW("mActiveContainers is inconsistent!");
San Mehat88705162010-01-15 09:26:28 -0800640 }
San Mehatb78a32c2010-01-10 13:02:12 -0800641 return 0;
642}
643
San Mehat4ba89482010-02-18 09:00:18 -0800644int VolumeManager::destroyAsec(const char *id, bool force) {
San Mehatb78a32c2010-01-10 13:02:12 -0800645 char asecFileName[255];
646 char mountPoint[255];
647
San Mehat3bb60202010-02-19 18:14:36 -0800648 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehat55013f72010-02-24 12:12:34 -0800649 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatb78a32c2010-01-10 13:02:12 -0800650
San Mehat0586d542010-01-12 15:38:59 -0800651 if (isMountpointMounted(mountPoint)) {
San Mehatd9a4e352010-03-12 13:32:47 -0800652 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700653 SLOGD("Unmounting container before destroy");
San Mehatd9a4e352010-03-12 13:32:47 -0800654 }
San Mehat4ba89482010-02-18 09:00:18 -0800655 if (unmountAsec(id, force)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700656 SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800657 return -1;
658 }
659 }
San Mehata19b2502010-01-06 10:33:53 -0800660
San Mehat0586d542010-01-12 15:38:59 -0800661 if (unlink(asecFileName)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700662 SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800663 return -1;
664 }
San Mehata19b2502010-01-06 10:33:53 -0800665
San Mehatd9a4e352010-03-12 13:32:47 -0800666 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700667 SLOGD("ASEC %s destroyed", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800668 }
San Mehata19b2502010-01-06 10:33:53 -0800669 return 0;
670}
671
672int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
673 char asecFileName[255];
674 char mountPoint[255];
675
San Mehat3bb60202010-02-19 18:14:36 -0800676 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
677 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800678
679 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700680 SLOGE("ASEC %s already mounted", id);
San Mehata19b2502010-01-06 10:33:53 -0800681 errno = EBUSY;
682 return -1;
683 }
684
San Mehatd9a4e352010-03-12 13:32:47 -0800685 char idHash[33];
686 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700687 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800688 return -1;
689 }
Kenny Root7b18a7b2010-03-15 13:13:41 -0700690
San Mehata19b2502010-01-06 10:33:53 -0800691 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800692 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
693 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700694 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800695 return -1;
696 }
San Mehatd9a4e352010-03-12 13:32:47 -0800697 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700698 SLOGD("New loop device created at %s", loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800699 }
San Mehatb78a32c2010-01-10 13:02:12 -0800700 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800701 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700702 SLOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800703 }
San Mehatb78a32c2010-01-10 13:02:12 -0800704 }
705
706 char dmDevice[255];
707 bool cleanupDm = false;
San Mehatfcf24fe2010-03-03 12:37:32 -0800708 int fd;
709 unsigned int nr_sec = 0;
710
711 if ((fd = open(loopDevice, O_RDWR)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700712 SLOGE("Failed to open loopdevice (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800713 Loop::destroyByDevice(loopDevice);
714 return -1;
715 }
716
717 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700718 SLOGE("Failed to get loop size (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800719 Loop::destroyByDevice(loopDevice);
720 close(fd);
721 return -1;
722 }
723
724 /*
725 * Validate superblock
726 */
727 struct asec_superblock sb;
728 memset(&sb, 0, sizeof(sb));
729 if (lseek(fd, ((nr_sec-1) * 512), SEEK_SET) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700730 SLOGE("lseek failed (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800731 close(fd);
732 Loop::destroyByDevice(loopDevice);
733 return -1;
734 }
735 if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700736 SLOGE("superblock read failed (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800737 close(fd);
738 Loop::destroyByDevice(loopDevice);
739 return -1;
740 }
741
742 close(fd);
743
San Mehatd9a4e352010-03-12 13:32:47 -0800744 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700745 SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatd9a4e352010-03-12 13:32:47 -0800746 }
San Mehatfcf24fe2010-03-03 12:37:32 -0800747 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
San Mehat97ac40e2010-03-24 10:24:19 -0700748 SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatfcf24fe2010-03-03 12:37:32 -0800749 Loop::destroyByDevice(loopDevice);
750 errno = EMEDIUMTYPE;
751 return -1;
752 }
753 nr_sec--; // We don't want the devmapping to extend onto our superblock
754
San Mehatb78a32c2010-01-10 13:02:12 -0800755 if (strcmp(key, "none")) {
San Mehatd9a4e352010-03-12 13:32:47 -0800756 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
757 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
San Mehatb78a32c2010-01-10 13:02:12 -0800758 dmDevice, sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700759 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800760 Loop::destroyByDevice(loopDevice);
761 return -1;
762 }
San Mehatd9a4e352010-03-12 13:32:47 -0800763 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700764 SLOGD("New devmapper instance created at %s", dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800765 }
San Mehatb78a32c2010-01-10 13:02:12 -0800766 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800767 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700768 SLOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800769 }
San Mehatb78a32c2010-01-10 13:02:12 -0800770 }
771 cleanupDm = true;
772 } else {
773 strcpy(dmDevice, loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800774 }
775
776 if (mkdir(mountPoint, 0777)) {
San Mehatb78a32c2010-01-10 13:02:12 -0800777 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -0700778 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800779 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800780 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800781 }
782 Loop::destroyByDevice(loopDevice);
783 return -1;
784 }
San Mehata19b2502010-01-06 10:33:53 -0800785 }
786
Kenny Roota3e06082010-08-27 08:31:35 -0700787 if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0,
San Mehatcff5ec32010-01-08 12:31:44 -0800788 0222, false)) {
789// 0227, false)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700790 SLOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800791 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800792 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800793 }
794 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800795 return -1;
796 }
797
Kenny Rootcbacf782010-09-24 15:11:48 -0700798 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehatd9a4e352010-03-12 13:32:47 -0800799 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700800 SLOGD("ASEC %s mounted", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800801 }
San Mehata19b2502010-01-06 10:33:53 -0800802 return 0;
803}
804
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700805/**
806 * Mounts an image file <code>img</code>.
807 */
Kenny Root508c0e12010-07-12 09:59:49 -0700808int VolumeManager::mountObb(const char *img, const char *key, int ownerUid) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700809 char mountPoint[255];
810
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700811 char idHash[33];
812 if (!asecHash(img, idHash, sizeof(idHash))) {
813 SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
814 return -1;
815 }
816
817 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
818
819 if (isMountpointMounted(mountPoint)) {
820 SLOGE("Image %s already mounted", img);
821 errno = EBUSY;
822 return -1;
823 }
824
825 char loopDevice[255];
826 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
827 if (Loop::create(idHash, img, loopDevice, sizeof(loopDevice))) {
828 SLOGE("Image loop device creation failed (%s)", strerror(errno));
829 return -1;
830 }
831 if (mDebug) {
832 SLOGD("New loop device created at %s", loopDevice);
833 }
834 } else {
835 if (mDebug) {
836 SLOGD("Found active loopback for %s at %s", img, loopDevice);
837 }
838 }
839
840 char dmDevice[255];
841 bool cleanupDm = false;
842 int fd;
843 unsigned int nr_sec = 0;
844
845 if ((fd = open(loopDevice, O_RDWR)) < 0) {
846 SLOGE("Failed to open loopdevice (%s)", strerror(errno));
847 Loop::destroyByDevice(loopDevice);
848 return -1;
849 }
850
851 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
852 SLOGE("Failed to get loop size (%s)", strerror(errno));
853 Loop::destroyByDevice(loopDevice);
854 close(fd);
855 return -1;
856 }
857
858 close(fd);
859
860 if (strcmp(key, "none")) {
861 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
862 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
863 dmDevice, sizeof(dmDevice))) {
864 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
865 Loop::destroyByDevice(loopDevice);
866 return -1;
867 }
868 if (mDebug) {
869 SLOGD("New devmapper instance created at %s", dmDevice);
870 }
871 } else {
872 if (mDebug) {
873 SLOGD("Found active devmapper for %s at %s", img, dmDevice);
874 }
875 }
876 cleanupDm = true;
877 } else {
878 strcpy(dmDevice, loopDevice);
879 }
880
881 if (mkdir(mountPoint, 0755)) {
882 if (errno != EEXIST) {
883 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
884 if (cleanupDm) {
885 Devmapper::destroy(idHash);
886 }
887 Loop::destroyByDevice(loopDevice);
888 return -1;
889 }
890 }
891
Kenny Roota3e06082010-08-27 08:31:35 -0700892 if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0,
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700893 0227, false)) {
894 SLOGE("Image mount failed (%s)", strerror(errno));
895 if (cleanupDm) {
896 Devmapper::destroy(idHash);
897 }
898 Loop::destroyByDevice(loopDevice);
899 return -1;
900 }
901
Kenny Rootcbacf782010-09-24 15:11:48 -0700902 mActiveContainers->push_back(new ContainerData(strdup(img), OBB));
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700903 if (mDebug) {
904 SLOGD("Image %s mounted", img);
905 }
906 return 0;
907}
908
San Mehat49e2bce2009-10-12 16:29:01 -0700909int VolumeManager::mountVolume(const char *label) {
910 Volume *v = lookupVolume(label);
911
912 if (!v) {
913 errno = ENOENT;
914 return -1;
915 }
916
San Mehata2677e42009-12-13 10:40:18 -0800917 return v->mountVol();
918}
919
Kenny Root508c0e12010-07-12 09:59:49 -0700920int VolumeManager::listMountedObbs(SocketClient* cli) {
921 char device[256];
922 char mount_path[256];
923 char rest[256];
924 FILE *fp;
925 char line[1024];
926
927 if (!(fp = fopen("/proc/mounts", "r"))) {
928 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
929 return -1;
930 }
931
932 // Create a string to compare against that has a trailing slash
933 int loopDirLen = sizeof(Volume::LOOPDIR);
934 char loopDir[loopDirLen + 2];
935 strcpy(loopDir, Volume::LOOPDIR);
936 loopDir[loopDirLen++] = '/';
937 loopDir[loopDirLen] = '\0';
938
939 while(fgets(line, sizeof(line), fp)) {
940 line[strlen(line)-1] = '\0';
941
942 /*
943 * Should look like:
944 * /dev/block/loop0 /mnt/obb/fc99df1323fd36424f864dcb76b76d65 ...
945 */
946 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
947
948 if (!strncmp(mount_path, loopDir, loopDirLen)) {
949 int fd = open(device, O_RDONLY);
950 if (fd >= 0) {
951 struct loop_info64 li;
952 if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
953 cli->sendMsg(ResponseCode::AsecListResult,
954 (const char*) li.lo_file_name, false);
955 }
956 close(fd);
957 }
958 }
959 }
960
961 fclose(fp);
962 return 0;
963}
964
San Mehata2677e42009-12-13 10:40:18 -0800965int VolumeManager::shareAvailable(const char *method, bool *avail) {
966
967 if (strcmp(method, "ums")) {
968 errno = ENOSYS;
969 return -1;
970 }
971
Mike Lockwood99635f62010-06-25 23:04:04 -0400972 *avail = massStorageAvailable();
San Mehata2677e42009-12-13 10:40:18 -0800973 return 0;
974}
975
San Mehateba65e92010-01-29 05:15:16 -0800976int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
977 Volume *v = lookupVolume(label);
978
979 if (!v) {
980 errno = ENOENT;
981 return -1;
982 }
983
984 if (strcmp(method, "ums")) {
985 errno = ENOSYS;
986 return -1;
987 }
988
989 if (v->getState() != Volume::State_Shared) {
San Mehateba65e92010-01-29 05:15:16 -0800990 *enabled = false;
San Mehatb9aed742010-02-04 15:07:01 -0800991 } else {
992 *enabled = true;
San Mehateba65e92010-01-29 05:15:16 -0800993 }
994 return 0;
995}
996
San Mehata2677e42009-12-13 10:40:18 -0800997int VolumeManager::simulate(const char *cmd, const char *arg) {
998
999 if (!strcmp(cmd, "ums")) {
1000 if (!strcmp(arg, "connect")) {
Mike Lockwood99635f62010-06-25 23:04:04 -04001001 notifyUmsAvailable(true);
San Mehata2677e42009-12-13 10:40:18 -08001002 } else if (!strcmp(arg, "disconnect")) {
Mike Lockwood99635f62010-06-25 23:04:04 -04001003 notifyUmsAvailable(false);
San Mehata2677e42009-12-13 10:40:18 -08001004 } else {
1005 errno = EINVAL;
1006 return -1;
1007 }
1008 } else {
1009 errno = EINVAL;
1010 return -1;
1011 }
1012 return 0;
1013}
1014
1015int VolumeManager::shareVolume(const char *label, const char *method) {
1016 Volume *v = lookupVolume(label);
1017
1018 if (!v) {
1019 errno = ENOENT;
1020 return -1;
1021 }
1022
1023 /*
1024 * Eventually, we'll want to support additional share back-ends,
1025 * some of which may work while the media is mounted. For now,
1026 * we just support UMS
1027 */
1028 if (strcmp(method, "ums")) {
1029 errno = ENOSYS;
1030 return -1;
1031 }
1032
1033 if (v->getState() == Volume::State_NoMedia) {
1034 errno = ENODEV;
1035 return -1;
1036 }
1037
San Mehat49e2bce2009-10-12 16:29:01 -07001038 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -08001039 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -07001040 errno = EBUSY;
1041 return -1;
1042 }
1043
Mike Lockwood2dfe2972010-09-17 18:50:51 -04001044 dev_t d = v->getShareDevice();
San Mehata2677e42009-12-13 10:40:18 -08001045 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
1046 // This volume does not support raw disk access
1047 errno = EINVAL;
1048 return -1;
1049 }
1050
1051 int fd;
1052 char nodepath[255];
1053 snprintf(nodepath,
1054 sizeof(nodepath), "/dev/block/vold/%d:%d",
1055 MAJOR(d), MINOR(d));
1056
San Mehat0cde53c2009-12-22 08:32:33 -08001057 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file",
1058 O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001059 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001060 return -1;
1061 }
1062
1063 if (write(fd, nodepath, strlen(nodepath)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001064 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001065 close(fd);
1066 return -1;
1067 }
1068
1069 close(fd);
1070 v->handleVolumeShared();
Mike Lockwooda28056b2010-10-28 15:21:24 -04001071 if (mUmsSharingCount++ == 0) {
1072 FILE* fp;
1073 mSavedDirtyRatio = -1; // in case we fail
1074 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1075 char line[16];
1076 if (fgets(line, sizeof(line), fp) && sscanf(line, "%d", &mSavedDirtyRatio)) {
1077 fprintf(fp, "%d\n", mUmsDirtyRatio);
1078 } else {
1079 SLOGE("Failed to read dirty_ratio (%s)", strerror(errno));
1080 }
1081 fclose(fp);
1082 } else {
1083 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1084 }
1085 }
San Mehata2677e42009-12-13 10:40:18 -08001086 return 0;
1087}
1088
1089int VolumeManager::unshareVolume(const char *label, const char *method) {
1090 Volume *v = lookupVolume(label);
1091
1092 if (!v) {
1093 errno = ENOENT;
1094 return -1;
1095 }
1096
1097 if (strcmp(method, "ums")) {
1098 errno = ENOSYS;
1099 return -1;
1100 }
1101
1102 if (v->getState() != Volume::State_Shared) {
1103 errno = EINVAL;
1104 return -1;
1105 }
1106
San Mehata2677e42009-12-13 10:40:18 -08001107 int fd;
San Mehat0cde53c2009-12-22 08:32:33 -08001108 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file", O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001109 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001110 return -1;
1111 }
1112
1113 char ch = 0;
1114 if (write(fd, &ch, 1) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001115 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001116 close(fd);
1117 return -1;
1118 }
1119
1120 close(fd);
1121 v->handleVolumeUnshared();
Mike Lockwooda28056b2010-10-28 15:21:24 -04001122 if (--mUmsSharingCount == 0 && mSavedDirtyRatio != -1) {
1123 FILE* fp;
1124 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1125 fprintf(fp, "%d\n", mSavedDirtyRatio);
1126 fclose(fp);
1127 } else {
1128 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1129 }
1130 mSavedDirtyRatio = -1;
1131 }
San Mehata2677e42009-12-13 10:40:18 -08001132 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -07001133}
1134
San Mehat4ba89482010-02-18 09:00:18 -08001135int VolumeManager::unmountVolume(const char *label, bool force) {
San Mehat49e2bce2009-10-12 16:29:01 -07001136 Volume *v = lookupVolume(label);
1137
1138 if (!v) {
1139 errno = ENOENT;
1140 return -1;
1141 }
1142
San Mehata2677e42009-12-13 10:40:18 -08001143 if (v->getState() == Volume::State_NoMedia) {
1144 errno = ENODEV;
1145 return -1;
1146 }
1147
San Mehat49e2bce2009-10-12 16:29:01 -07001148 if (v->getState() != Volume::State_Mounted) {
San Mehat97ac40e2010-03-24 10:24:19 -07001149 SLOGW("Attempt to unmount volume which isn't mounted (%d)\n",
San Mehata2677e42009-12-13 10:40:18 -08001150 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -07001151 errno = EBUSY;
1152 return -1;
1153 }
1154
San Mehat1a06eda2010-04-15 12:58:50 -07001155 cleanupAsec(v, force);
San Mehat88705162010-01-15 09:26:28 -08001156
San Mehat4ba89482010-02-18 09:00:18 -08001157 return v->unmountVol(force);
San Mehat49e2bce2009-10-12 16:29:01 -07001158}
1159
San Mehata2677e42009-12-13 10:40:18 -08001160/*
1161 * Looks up a volume by it's label or mount-point
1162 */
San Mehat49e2bce2009-10-12 16:29:01 -07001163Volume *VolumeManager::lookupVolume(const char *label) {
1164 VolumeCollection::iterator i;
1165
1166 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -08001167 if (label[0] == '/') {
1168 if (!strcmp(label, (*i)->getMountpoint()))
1169 return (*i);
1170 } else {
1171 if (!strcmp(label, (*i)->getLabel()))
1172 return (*i);
1173 }
San Mehat49e2bce2009-10-12 16:29:01 -07001174 }
1175 return NULL;
1176}
San Mehata19b2502010-01-06 10:33:53 -08001177
1178bool VolumeManager::isMountpointMounted(const char *mp)
1179{
1180 char device[256];
1181 char mount_path[256];
1182 char rest[256];
1183 FILE *fp;
1184 char line[1024];
1185
1186 if (!(fp = fopen("/proc/mounts", "r"))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001187 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001188 return false;
1189 }
1190
1191 while(fgets(line, sizeof(line), fp)) {
1192 line[strlen(line)-1] = '\0';
1193 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1194 if (!strcmp(mount_path, mp)) {
1195 fclose(fp);
1196 return true;
1197 }
San Mehata19b2502010-01-06 10:33:53 -08001198 }
1199
1200 fclose(fp);
1201 return false;
1202}
1203
San Mehat1a06eda2010-04-15 12:58:50 -07001204int VolumeManager::cleanupAsec(Volume *v, bool force) {
1205 while(mActiveContainers->size()) {
1206 AsecIdCollection::iterator it = mActiveContainers->begin();
Kenny Rootcbacf782010-09-24 15:11:48 -07001207 ContainerData* cd = *it;
1208 SLOGI("Unmounting ASEC %s (dependant on %s)", cd->id, v->getMountpoint());
1209 if (cd->type == ASEC) {
1210 if (unmountAsec(cd->id, force)) {
1211 SLOGE("Failed to unmount ASEC %s (%s)", cd->id, strerror(errno));
1212 return -1;
1213 }
1214 } else if (cd->type == OBB) {
1215 if (unmountObb(cd->id, force)) {
1216 SLOGE("Failed to unmount OBB %s (%s)", cd->id, strerror(errno));
1217 return -1;
1218 }
1219 } else {
1220 SLOGE("Unknown container type %d!", cd->type);
San Mehat1a06eda2010-04-15 12:58:50 -07001221 return -1;
1222 }
1223 }
1224 return 0;
1225}
1226