blob: 071e0273b466a6dfd3e7e50a434d6358a82e7a03 [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"
Ken Sumrall29d8da82011-05-18 17:20:07 -070044#include "cryptfs.h"
San Mehat23969932010-01-09 07:08:06 -080045
San Mehatf1b736b2009-10-10 17:22:08 -070046VolumeManager *VolumeManager::sInstance = NULL;
47
48VolumeManager *VolumeManager::Instance() {
49 if (!sInstance)
50 sInstance = new VolumeManager();
51 return sInstance;
52}
53
54VolumeManager::VolumeManager() {
San Mehatd9a4e352010-03-12 13:32:47 -080055 mDebug = false;
San Mehatf1b736b2009-10-10 17:22:08 -070056 mVolumes = new VolumeCollection();
San Mehat88705162010-01-15 09:26:28 -080057 mActiveContainers = new AsecIdCollection();
San Mehatf1b736b2009-10-10 17:22:08 -070058 mBroadcaster = NULL;
Mike Lockwood99635f62010-06-25 23:04:04 -040059 mUsbMassStorageEnabled = false;
60 mUsbConnected = false;
Mike Lockwooda28056b2010-10-28 15:21:24 -040061 mUmsSharingCount = 0;
62 mSavedDirtyRatio = -1;
63 // set dirty ratio to 0 when UMS is active
64 mUmsDirtyRatio = 0;
Mike Lockwood99635f62010-06-25 23:04:04 -040065
66 readInitialState();
67}
68
69void VolumeManager::readInitialState() {
70 FILE *fp;
71 char state[255];
72
73 /*
74 * Read the initial mass storage enabled state
75 */
76 if ((fp = fopen("/sys/devices/virtual/usb_composite/usb_mass_storage/enable", "r"))) {
77 if (fgets(state, sizeof(state), fp)) {
78 mUsbMassStorageEnabled = !strncmp(state, "1", 1);
79 } else {
80 SLOGE("Failed to read usb_mass_storage enabled state (%s)", strerror(errno));
81 }
82 fclose(fp);
83 } else {
84 SLOGD("USB mass storage support is not enabled in the kernel");
85 }
86
87 /*
88 * Read the initial USB connected state
89 */
90 if ((fp = fopen("/sys/devices/virtual/switch/usb_configuration/state", "r"))) {
91 if (fgets(state, sizeof(state), fp)) {
92 mUsbConnected = !strncmp(state, "1", 1);
93 } else {
94 SLOGE("Failed to read usb_configuration switch (%s)", strerror(errno));
95 }
96 fclose(fp);
97 } else {
98 SLOGD("usb_configuration switch is not enabled in the kernel");
99 }
San Mehatf1b736b2009-10-10 17:22:08 -0700100}
101
102VolumeManager::~VolumeManager() {
San Mehat88705162010-01-15 09:26:28 -0800103 delete mVolumes;
104 delete mActiveContainers;
San Mehatf1b736b2009-10-10 17:22:08 -0700105}
106
Kenny Root7b18a7b2010-03-15 13:13:41 -0700107char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700108 static const char* digits = "0123456789abcdef";
109
Kenny Root7b18a7b2010-03-15 13:13:41 -0700110 unsigned char sig[MD5_DIGEST_LENGTH];
111
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700112 if (buffer == NULL) {
113 SLOGE("Destination buffer is NULL");
114 errno = ESPIPE;
115 return NULL;
116 } else if (id == NULL) {
117 SLOGE("Source buffer is NULL");
118 errno = ESPIPE;
119 return NULL;
120 } else if (len < MD5_ASCII_LENGTH_PLUS_NULL) {
121 SLOGE("Target hash buffer size < %d bytes (%d)",
122 MD5_ASCII_LENGTH_PLUS_NULL, len);
San Mehatd9a4e352010-03-12 13:32:47 -0800123 errno = ESPIPE;
124 return NULL;
125 }
Kenny Root7b18a7b2010-03-15 13:13:41 -0700126
127 MD5(reinterpret_cast<const unsigned char*>(id), strlen(id), sig);
San Mehatd9a4e352010-03-12 13:32:47 -0800128
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700129 char *p = buffer;
Kenny Root7b18a7b2010-03-15 13:13:41 -0700130 for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700131 *p++ = digits[sig[i] >> 4];
132 *p++ = digits[sig[i] & 0x0F];
San Mehatd9a4e352010-03-12 13:32:47 -0800133 }
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700134 *p = '\0';
San Mehatd9a4e352010-03-12 13:32:47 -0800135
136 return buffer;
137}
138
139void VolumeManager::setDebug(bool enable) {
140 mDebug = enable;
141 VolumeCollection::iterator it;
142 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
143 (*it)->setDebug(enable);
144 }
145}
146
San Mehatf1b736b2009-10-10 17:22:08 -0700147int VolumeManager::start() {
148 return 0;
149}
150
151int VolumeManager::stop() {
152 return 0;
153}
154
155int VolumeManager::addVolume(Volume *v) {
156 mVolumes->push_back(v);
157 return 0;
158}
159
Mike Lockwood99635f62010-06-25 23:04:04 -0400160void VolumeManager::notifyUmsAvailable(bool available) {
San Mehata2677e42009-12-13 10:40:18 -0800161 char msg[255];
162
San Mehata2677e42009-12-13 10:40:18 -0800163 snprintf(msg, sizeof(msg), "Share method ums now %s",
Mike Lockwood99635f62010-06-25 23:04:04 -0400164 (available ? "available" : "unavailable"));
165 SLOGD(msg);
San Mehata2677e42009-12-13 10:40:18 -0800166 getBroadcaster()->sendBroadcast(ResponseCode::ShareAvailabilityChange,
167 msg, false);
168}
169
170void VolumeManager::handleSwitchEvent(NetlinkEvent *evt) {
San Mehat0cde53c2009-12-22 08:32:33 -0800171 const char *devpath = evt->findParam("DEVPATH");
San Mehata2677e42009-12-13 10:40:18 -0800172 const char *name = evt->findParam("SWITCH_NAME");
173 const char *state = evt->findParam("SWITCH_STATE");
174
San Mehat0cde53c2009-12-22 08:32:33 -0800175 if (!name || !state) {
San Mehat97ac40e2010-03-24 10:24:19 -0700176 SLOGW("Switch %s event missing name/state info", devpath);
San Mehat0cde53c2009-12-22 08:32:33 -0800177 return;
178 }
179
Mike Lockwood99635f62010-06-25 23:04:04 -0400180 bool oldAvailable = massStorageAvailable();
181 if (!strcmp(name, "usb_configuration")) {
182 mUsbConnected = !strcmp(state, "1");
183 SLOGD("USB %s", mUsbConnected ? "connected" : "disconnected");
184 bool newAvailable = massStorageAvailable();
185 if (newAvailable != oldAvailable) {
186 notifyUmsAvailable(newAvailable);
San Mehata2677e42009-12-13 10:40:18 -0800187 }
San Mehata2677e42009-12-13 10:40:18 -0800188 }
189}
Mike Lockwood99635f62010-06-25 23:04:04 -0400190void VolumeManager::handleUsbCompositeEvent(NetlinkEvent *evt) {
191 const char *function = evt->findParam("FUNCTION");
192 const char *enabled = evt->findParam("ENABLED");
193
194 if (!function || !enabled) {
195 SLOGW("usb_composite event missing function/enabled info");
196 return;
197 }
198
199 if (!strcmp(function, "usb_mass_storage")) {
200 bool oldAvailable = massStorageAvailable();
201 mUsbMassStorageEnabled = !strcmp(enabled, "1");
202 SLOGD("usb_mass_storage function %s", mUsbMassStorageEnabled ? "enabled" : "disabled");
203 bool newAvailable = massStorageAvailable();
204 if (newAvailable != oldAvailable) {
205 notifyUmsAvailable(newAvailable);
206 }
207 }
208}
San Mehata2677e42009-12-13 10:40:18 -0800209
San Mehatfd7f5872009-10-12 11:32:47 -0700210void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
211 const char *devpath = evt->findParam("DEVPATH");
San Mehatf1b736b2009-10-10 17:22:08 -0700212
San Mehatfd7f5872009-10-12 11:32:47 -0700213 /* Lookup a volume to handle this device */
San Mehatf1b736b2009-10-10 17:22:08 -0700214 VolumeCollection::iterator it;
215 bool hit = false;
216 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
San Mehatfd7f5872009-10-12 11:32:47 -0700217 if (!(*it)->handleBlockEvent(evt)) {
San Mehata2677e42009-12-13 10:40:18 -0800218#ifdef NETLINK_DEBUG
San Mehat97ac40e2010-03-24 10:24:19 -0700219 SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
San Mehata2677e42009-12-13 10:40:18 -0800220#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700221 hit = true;
San Mehatf1b736b2009-10-10 17:22:08 -0700222 break;
223 }
224 }
225
226 if (!hit) {
San Mehata2677e42009-12-13 10:40:18 -0800227#ifdef NETLINK_DEBUG
San Mehat97ac40e2010-03-24 10:24:19 -0700228 SLOGW("No volumes handled block event for '%s'", devpath);
San Mehata2677e42009-12-13 10:40:18 -0800229#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700230 }
231}
232
San Mehatf1b736b2009-10-10 17:22:08 -0700233int VolumeManager::listVolumes(SocketClient *cli) {
234 VolumeCollection::iterator i;
235
236 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
237 char *buffer;
238 asprintf(&buffer, "%s %s %d",
239 (*i)->getLabel(), (*i)->getMountpoint(),
240 (*i)->getState());
San Mehata2677e42009-12-13 10:40:18 -0800241 cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
San Mehatf1b736b2009-10-10 17:22:08 -0700242 free(buffer);
243 }
San Mehata2677e42009-12-13 10:40:18 -0800244 cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
San Mehatf1b736b2009-10-10 17:22:08 -0700245 return 0;
246}
San Mehat49e2bce2009-10-12 16:29:01 -0700247
San Mehata2677e42009-12-13 10:40:18 -0800248int VolumeManager::formatVolume(const char *label) {
249 Volume *v = lookupVolume(label);
250
251 if (!v) {
252 errno = ENOENT;
253 return -1;
254 }
255
256 return v->formatVol();
257}
258
Kenny Root508c0e12010-07-12 09:59:49 -0700259int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) {
260 char idHash[33];
261 if (!asecHash(sourceFile, idHash, sizeof(idHash))) {
262 SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno));
263 return -1;
264 }
265
266 memset(mountPath, 0, mountPathLen);
267 snprintf(mountPath, mountPathLen, "%s/%s", Volume::LOOPDIR, idHash);
268
269 if (access(mountPath, F_OK)) {
270 errno = ENOENT;
271 return -1;
272 }
273
274 return 0;
275}
276
San Mehata19b2502010-01-06 10:33:53 -0800277int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
San Mehat88ac2c02010-03-23 11:15:58 -0700278 char asecFileName[255];
279 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
280
281 memset(buffer, 0, maxlen);
282 if (access(asecFileName, F_OK)) {
283 errno = ENOENT;
284 return -1;
285 }
San Mehata19b2502010-01-06 10:33:53 -0800286
San Mehat3bb60202010-02-19 18:14:36 -0800287 snprintf(buffer, maxlen, "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800288 return 0;
289}
290
San Mehat8b8f71b2010-01-11 09:17:25 -0800291int VolumeManager::createAsec(const char *id, unsigned int numSectors,
San Mehata19b2502010-01-06 10:33:53 -0800292 const char *fstype, const char *key, int ownerUid) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800293 struct asec_superblock sb;
294 memset(&sb, 0, sizeof(sb));
295
296 sb.magic = ASEC_SB_MAGIC;
297 sb.ver = ASEC_SB_VER;
San Mehata19b2502010-01-06 10:33:53 -0800298
San Mehatd31e3802010-02-18 08:37:45 -0800299 if (numSectors < ((1024*1024)/512)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700300 SLOGE("Invalid container size specified (%d sectors)", numSectors);
San Mehatd31e3802010-02-18 08:37:45 -0800301 errno = EINVAL;
302 return -1;
303 }
304
San Mehata19b2502010-01-06 10:33:53 -0800305 if (lookupVolume(id)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700306 SLOGE("ASEC id '%s' currently exists", id);
San Mehata19b2502010-01-06 10:33:53 -0800307 errno = EADDRINUSE;
308 return -1;
309 }
310
311 char asecFileName[255];
San Mehat3bb60202010-02-19 18:14:36 -0800312 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800313
314 if (!access(asecFileName, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700315 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
San Mehata19b2502010-01-06 10:33:53 -0800316 asecFileName, strerror(errno));
317 errno = EADDRINUSE;
318 return -1;
319 }
320
San Mehatfcf24fe2010-03-03 12:37:32 -0800321 /*
322 * Add some headroom
323 */
324 unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
325 unsigned numImgSectors = numSectors + fatSize + 2;
326
327 if (numImgSectors % 63) {
328 numImgSectors += (63 - (numImgSectors % 63));
329 }
330
331 // Add +1 for our superblock which is at the end
332 if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700333 SLOGE("ASEC image file creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800334 return -1;
335 }
336
San Mehatd9a4e352010-03-12 13:32:47 -0800337 char idHash[33];
338 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700339 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800340 unlink(asecFileName);
341 return -1;
342 }
343
San Mehata19b2502010-01-06 10:33:53 -0800344 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800345 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700346 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800347 unlink(asecFileName);
348 return -1;
349 }
350
San Mehatb78a32c2010-01-10 13:02:12 -0800351 char dmDevice[255];
352 bool cleanupDm = false;
San Mehata19b2502010-01-06 10:33:53 -0800353
San Mehatb78a32c2010-01-10 13:02:12 -0800354 if (strcmp(key, "none")) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800355 // XXX: This is all we support for now
356 sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
San Mehatd9a4e352010-03-12 13:32:47 -0800357 if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
San Mehatb78a32c2010-01-10 13:02:12 -0800358 sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700359 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800360 Loop::destroyByDevice(loopDevice);
361 unlink(asecFileName);
362 return -1;
363 }
364 cleanupDm = true;
365 } else {
San Mehatfcf24fe2010-03-03 12:37:32 -0800366 sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
San Mehatb78a32c2010-01-10 13:02:12 -0800367 strcpy(dmDevice, loopDevice);
368 }
369
San Mehatfcf24fe2010-03-03 12:37:32 -0800370 /*
371 * Drop down the superblock at the end of the file
372 */
373
374 int sbfd = open(loopDevice, O_RDWR);
375 if (sbfd < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700376 SLOGE("Failed to open new DM device for superblock write (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800377 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800378 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800379 }
380 Loop::destroyByDevice(loopDevice);
381 unlink(asecFileName);
382 return -1;
383 }
384
385 if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
386 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700387 SLOGE("Failed to lseek for superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800388 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800389 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800390 }
391 Loop::destroyByDevice(loopDevice);
392 unlink(asecFileName);
393 return -1;
394 }
395
396 if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) {
397 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700398 SLOGE("Failed to write superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800399 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800400 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800401 }
402 Loop::destroyByDevice(loopDevice);
403 unlink(asecFileName);
404 return -1;
405 }
406 close(sbfd);
407
San Mehata1091cb2010-02-28 20:17:20 -0800408 if (strcmp(fstype, "none")) {
409 if (strcmp(fstype, "fat")) {
San Mehat97ac40e2010-03-24 10:24:19 -0700410 SLOGW("Unknown fstype '%s' specified for container", fstype);
San Mehatb78a32c2010-01-10 13:02:12 -0800411 }
San Mehata19b2502010-01-06 10:33:53 -0800412
San Mehatfcf24fe2010-03-03 12:37:32 -0800413 if (Fat::format(dmDevice, numImgSectors)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700414 SLOGE("ASEC FAT format failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800415 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800416 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800417 }
San Mehateb13a902010-01-07 12:12:50 -0800418 Loop::destroyByDevice(loopDevice);
419 unlink(asecFileName);
420 return -1;
421 }
San Mehata1091cb2010-02-28 20:17:20 -0800422 char mountPoint[255];
San Mehata19b2502010-01-06 10:33:53 -0800423
San Mehata1091cb2010-02-28 20:17:20 -0800424 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
425 if (mkdir(mountPoint, 0777)) {
426 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -0700427 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800428 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800429 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800430 }
431 Loop::destroyByDevice(loopDevice);
432 unlink(asecFileName);
433 return -1;
434 }
San Mehatb78a32c2010-01-10 13:02:12 -0800435 }
San Mehata1091cb2010-02-28 20:17:20 -0800436
Kenny Roota3e06082010-08-27 08:31:35 -0700437 if (Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid,
San Mehata1091cb2010-02-28 20:17:20 -0800438 0, 0000, false)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700439 SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800440 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800441 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800442 }
443 Loop::destroyByDevice(loopDevice);
444 unlink(asecFileName);
445 return -1;
446 }
447 } else {
San Mehat97ac40e2010-03-24 10:24:19 -0700448 SLOGI("Created raw secure container %s (no filesystem)", id);
San Mehata19b2502010-01-06 10:33:53 -0800449 }
San Mehat88705162010-01-15 09:26:28 -0800450
Kenny Rootcbacf782010-09-24 15:11:48 -0700451 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehata19b2502010-01-06 10:33:53 -0800452 return 0;
453}
454
455int VolumeManager::finalizeAsec(const char *id) {
456 char asecFileName[255];
457 char loopDevice[255];
458 char mountPoint[255];
459
San Mehat3bb60202010-02-19 18:14:36 -0800460 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800461
San Mehatd9a4e352010-03-12 13:32:47 -0800462 char idHash[33];
463 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700464 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800465 return -1;
466 }
467
468 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700469 SLOGE("Unable to finalize %s (%s)", id, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800470 return -1;
471 }
472
San Mehat3bb60202010-02-19 18:14:36 -0800473 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatfff0b472010-01-06 19:19:46 -0800474 // XXX:
Kenny Roota3e06082010-08-27 08:31:35 -0700475 if (Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700476 SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800477 return -1;
478 }
479
San Mehatd9a4e352010-03-12 13:32:47 -0800480 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700481 SLOGD("ASEC %s finalized", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800482 }
San Mehata19b2502010-01-06 10:33:53 -0800483 return 0;
484}
485
San Mehat048b0802010-01-23 08:17:06 -0800486int VolumeManager::renameAsec(const char *id1, const char *id2) {
487 char *asecFilename1;
488 char *asecFilename2;
489 char mountPoint[255];
490
San Mehat3bb60202010-02-19 18:14:36 -0800491 asprintf(&asecFilename1, "%s/%s.asec", Volume::SEC_ASECDIR, id1);
492 asprintf(&asecFilename2, "%s/%s.asec", Volume::SEC_ASECDIR, id2);
San Mehat048b0802010-01-23 08:17:06 -0800493
San Mehat3bb60202010-02-19 18:14:36 -0800494 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
San Mehat048b0802010-01-23 08:17:06 -0800495 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700496 SLOGW("Rename attempt when src mounted");
San Mehat048b0802010-01-23 08:17:06 -0800497 errno = EBUSY;
498 goto out_err;
499 }
500
San Mehat96956ed2010-02-24 08:42:51 -0800501 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2);
502 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700503 SLOGW("Rename attempt when dst mounted");
San Mehat96956ed2010-02-24 08:42:51 -0800504 errno = EBUSY;
505 goto out_err;
506 }
507
San Mehat048b0802010-01-23 08:17:06 -0800508 if (!access(asecFilename2, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700509 SLOGE("Rename attempt when dst exists");
San Mehat048b0802010-01-23 08:17:06 -0800510 errno = EADDRINUSE;
511 goto out_err;
512 }
513
514 if (rename(asecFilename1, asecFilename2)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700515 SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
San Mehat048b0802010-01-23 08:17:06 -0800516 goto out_err;
517 }
518
519 free(asecFilename1);
520 free(asecFilename2);
521 return 0;
522
523out_err:
524 free(asecFilename1);
525 free(asecFilename2);
526 return -1;
527}
528
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700529#define UNMOUNT_RETRIES 5
530#define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
San Mehat4ba89482010-02-18 09:00:18 -0800531int VolumeManager::unmountAsec(const char *id, bool force) {
San Mehata19b2502010-01-06 10:33:53 -0800532 char asecFileName[255];
533 char mountPoint[255];
534
San Mehat3bb60202010-02-19 18:14:36 -0800535 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
536 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800537
San Mehatd9a4e352010-03-12 13:32:47 -0800538 char idHash[33];
539 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700540 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800541 return -1;
542 }
543
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700544 return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
545}
546
Kenny Root508c0e12010-07-12 09:59:49 -0700547int VolumeManager::unmountObb(const char *fileName, bool force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700548 char mountPoint[255];
549
550 char idHash[33];
551 if (!asecHash(fileName, idHash, sizeof(idHash))) {
552 SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
553 return -1;
554 }
555
556 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
557
558 return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
559}
560
561int VolumeManager::unmountLoopImage(const char *id, const char *idHash,
562 const char *fileName, const char *mountPoint, bool force) {
San Mehat0586d542010-01-12 15:38:59 -0800563 if (!isMountpointMounted(mountPoint)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700564 SLOGE("Unmount request for %s when not mounted", id);
Kenny Root918e5f92010-09-30 18:00:52 -0700565 errno = ENOENT;
San Mehatb78a32c2010-01-10 13:02:12 -0800566 return -1;
567 }
San Mehat23969932010-01-09 07:08:06 -0800568
San Mehatb78a32c2010-01-10 13:02:12 -0800569 int i, rc;
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700570 for (i = 1; i <= UNMOUNT_RETRIES; i++) {
San Mehatb78a32c2010-01-10 13:02:12 -0800571 rc = umount(mountPoint);
572 if (!rc) {
573 break;
San Mehata19b2502010-01-06 10:33:53 -0800574 }
San Mehatb78a32c2010-01-10 13:02:12 -0800575 if (rc && (errno == EINVAL || errno == ENOENT)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700576 SLOGI("Container %s unmounted OK", id);
San Mehatb78a32c2010-01-10 13:02:12 -0800577 rc = 0;
578 break;
San Mehata19b2502010-01-06 10:33:53 -0800579 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700580 SLOGW("%s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -0800581 id, i, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800582
San Mehat4ba89482010-02-18 09:00:18 -0800583 int action = 0; // default is to just complain
584
585 if (force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700586 if (i > (UNMOUNT_RETRIES - 2))
San Mehat4ba89482010-02-18 09:00:18 -0800587 action = 2; // SIGKILL
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700588 else if (i > (UNMOUNT_RETRIES - 3))
San Mehat4ba89482010-02-18 09:00:18 -0800589 action = 1; // SIGHUP
590 }
San Mehat8c940ef2010-02-13 14:19:53 -0800591
San Mehat586536c2010-02-16 17:12:00 -0800592 Process::killProcessesWithOpenFiles(mountPoint, action);
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700593 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehatb78a32c2010-01-10 13:02:12 -0800594 }
595
596 if (rc) {
San Mehat4ba89482010-02-18 09:00:18 -0800597 errno = EBUSY;
San Mehat97ac40e2010-03-24 10:24:19 -0700598 SLOGE("Failed to unmount container %s (%s)", id, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800599 return -1;
600 }
601
San Mehat12f4b892010-02-24 11:43:22 -0800602 int retries = 10;
603
604 while(retries--) {
605 if (!rmdir(mountPoint)) {
606 break;
607 }
608
San Mehat97ac40e2010-03-24 10:24:19 -0700609 SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700610 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehat12f4b892010-02-24 11:43:22 -0800611 }
612
613 if (!retries) {
San Mehat97ac40e2010-03-24 10:24:19 -0700614 SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
San Mehatf5c61982010-02-03 11:04:46 -0800615 }
San Mehat88705162010-01-15 09:26:28 -0800616
San Mehatd9a4e352010-03-12 13:32:47 -0800617 if (Devmapper::destroy(idHash) && errno != ENXIO) {
San Mehat97ac40e2010-03-24 10:24:19 -0700618 SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800619 }
620
621 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800622 if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800623 Loop::destroyByDevice(loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800624 } else {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700625 SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800626 }
San Mehat88705162010-01-15 09:26:28 -0800627
628 AsecIdCollection::iterator it;
629 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
Kenny Rootcbacf782010-09-24 15:11:48 -0700630 ContainerData* cd = *it;
631 if (!strcmp(cd->id, id)) {
San Mehat88705162010-01-15 09:26:28 -0800632 free(*it);
633 mActiveContainers->erase(it);
634 break;
635 }
636 }
637 if (it == mActiveContainers->end()) {
San Mehat97ac40e2010-03-24 10:24:19 -0700638 SLOGW("mActiveContainers is inconsistent!");
San Mehat88705162010-01-15 09:26:28 -0800639 }
San Mehatb78a32c2010-01-10 13:02:12 -0800640 return 0;
641}
642
San Mehat4ba89482010-02-18 09:00:18 -0800643int VolumeManager::destroyAsec(const char *id, bool force) {
San Mehatb78a32c2010-01-10 13:02:12 -0800644 char asecFileName[255];
645 char mountPoint[255];
646
San Mehat3bb60202010-02-19 18:14:36 -0800647 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehat55013f72010-02-24 12:12:34 -0800648 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatb78a32c2010-01-10 13:02:12 -0800649
San Mehat0586d542010-01-12 15:38:59 -0800650 if (isMountpointMounted(mountPoint)) {
San Mehatd9a4e352010-03-12 13:32:47 -0800651 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700652 SLOGD("Unmounting container before destroy");
San Mehatd9a4e352010-03-12 13:32:47 -0800653 }
San Mehat4ba89482010-02-18 09:00:18 -0800654 if (unmountAsec(id, force)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700655 SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800656 return -1;
657 }
658 }
San Mehata19b2502010-01-06 10:33:53 -0800659
San Mehat0586d542010-01-12 15:38:59 -0800660 if (unlink(asecFileName)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700661 SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800662 return -1;
663 }
San Mehata19b2502010-01-06 10:33:53 -0800664
San Mehatd9a4e352010-03-12 13:32:47 -0800665 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700666 SLOGD("ASEC %s destroyed", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800667 }
San Mehata19b2502010-01-06 10:33:53 -0800668 return 0;
669}
670
671int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
672 char asecFileName[255];
673 char mountPoint[255];
674
San Mehat3bb60202010-02-19 18:14:36 -0800675 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
676 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800677
678 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700679 SLOGE("ASEC %s already mounted", id);
San Mehata19b2502010-01-06 10:33:53 -0800680 errno = EBUSY;
681 return -1;
682 }
683
San Mehatd9a4e352010-03-12 13:32:47 -0800684 char idHash[33];
685 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700686 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800687 return -1;
688 }
Kenny Root7b18a7b2010-03-15 13:13:41 -0700689
San Mehata19b2502010-01-06 10:33:53 -0800690 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800691 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
692 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700693 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800694 return -1;
695 }
San Mehatd9a4e352010-03-12 13:32:47 -0800696 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700697 SLOGD("New loop device created at %s", loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800698 }
San Mehatb78a32c2010-01-10 13:02:12 -0800699 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800700 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700701 SLOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800702 }
San Mehatb78a32c2010-01-10 13:02:12 -0800703 }
704
705 char dmDevice[255];
706 bool cleanupDm = false;
San Mehatfcf24fe2010-03-03 12:37:32 -0800707 int fd;
708 unsigned int nr_sec = 0;
709
710 if ((fd = open(loopDevice, O_RDWR)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700711 SLOGE("Failed to open loopdevice (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800712 Loop::destroyByDevice(loopDevice);
713 return -1;
714 }
715
716 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700717 SLOGE("Failed to get loop size (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800718 Loop::destroyByDevice(loopDevice);
719 close(fd);
720 return -1;
721 }
722
723 /*
724 * Validate superblock
725 */
726 struct asec_superblock sb;
727 memset(&sb, 0, sizeof(sb));
728 if (lseek(fd, ((nr_sec-1) * 512), SEEK_SET) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700729 SLOGE("lseek failed (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800730 close(fd);
731 Loop::destroyByDevice(loopDevice);
732 return -1;
733 }
734 if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700735 SLOGE("superblock read failed (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800736 close(fd);
737 Loop::destroyByDevice(loopDevice);
738 return -1;
739 }
740
741 close(fd);
742
San Mehatd9a4e352010-03-12 13:32:47 -0800743 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700744 SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatd9a4e352010-03-12 13:32:47 -0800745 }
San Mehatfcf24fe2010-03-03 12:37:32 -0800746 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
San Mehat97ac40e2010-03-24 10:24:19 -0700747 SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatfcf24fe2010-03-03 12:37:32 -0800748 Loop::destroyByDevice(loopDevice);
749 errno = EMEDIUMTYPE;
750 return -1;
751 }
752 nr_sec--; // We don't want the devmapping to extend onto our superblock
753
San Mehatb78a32c2010-01-10 13:02:12 -0800754 if (strcmp(key, "none")) {
San Mehatd9a4e352010-03-12 13:32:47 -0800755 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
756 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
San Mehatb78a32c2010-01-10 13:02:12 -0800757 dmDevice, sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700758 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800759 Loop::destroyByDevice(loopDevice);
760 return -1;
761 }
San Mehatd9a4e352010-03-12 13:32:47 -0800762 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700763 SLOGD("New devmapper instance created at %s", dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800764 }
San Mehatb78a32c2010-01-10 13:02:12 -0800765 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800766 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700767 SLOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800768 }
San Mehatb78a32c2010-01-10 13:02:12 -0800769 }
770 cleanupDm = true;
771 } else {
772 strcpy(dmDevice, loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800773 }
774
775 if (mkdir(mountPoint, 0777)) {
San Mehatb78a32c2010-01-10 13:02:12 -0800776 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -0700777 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800778 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800779 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800780 }
781 Loop::destroyByDevice(loopDevice);
782 return -1;
783 }
San Mehata19b2502010-01-06 10:33:53 -0800784 }
785
Kenny Roota3e06082010-08-27 08:31:35 -0700786 if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0,
San Mehatcff5ec32010-01-08 12:31:44 -0800787 0222, false)) {
788// 0227, false)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700789 SLOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800790 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800791 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800792 }
793 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800794 return -1;
795 }
796
Kenny Rootcbacf782010-09-24 15:11:48 -0700797 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehatd9a4e352010-03-12 13:32:47 -0800798 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700799 SLOGD("ASEC %s mounted", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800800 }
San Mehata19b2502010-01-06 10:33:53 -0800801 return 0;
802}
803
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700804/**
805 * Mounts an image file <code>img</code>.
806 */
Kenny Root508c0e12010-07-12 09:59:49 -0700807int VolumeManager::mountObb(const char *img, const char *key, int ownerUid) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700808 char mountPoint[255];
809
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700810 char idHash[33];
811 if (!asecHash(img, idHash, sizeof(idHash))) {
812 SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
813 return -1;
814 }
815
816 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
817
818 if (isMountpointMounted(mountPoint)) {
819 SLOGE("Image %s already mounted", img);
820 errno = EBUSY;
821 return -1;
822 }
823
824 char loopDevice[255];
825 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
826 if (Loop::create(idHash, img, loopDevice, sizeof(loopDevice))) {
827 SLOGE("Image loop device creation failed (%s)", strerror(errno));
828 return -1;
829 }
830 if (mDebug) {
831 SLOGD("New loop device created at %s", loopDevice);
832 }
833 } else {
834 if (mDebug) {
835 SLOGD("Found active loopback for %s at %s", img, loopDevice);
836 }
837 }
838
839 char dmDevice[255];
840 bool cleanupDm = false;
841 int fd;
842 unsigned int nr_sec = 0;
843
844 if ((fd = open(loopDevice, O_RDWR)) < 0) {
845 SLOGE("Failed to open loopdevice (%s)", strerror(errno));
846 Loop::destroyByDevice(loopDevice);
847 return -1;
848 }
849
850 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
851 SLOGE("Failed to get loop size (%s)", strerror(errno));
852 Loop::destroyByDevice(loopDevice);
853 close(fd);
854 return -1;
855 }
856
857 close(fd);
858
859 if (strcmp(key, "none")) {
860 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
861 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
862 dmDevice, sizeof(dmDevice))) {
863 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
864 Loop::destroyByDevice(loopDevice);
865 return -1;
866 }
867 if (mDebug) {
868 SLOGD("New devmapper instance created at %s", dmDevice);
869 }
870 } else {
871 if (mDebug) {
872 SLOGD("Found active devmapper for %s at %s", img, dmDevice);
873 }
874 }
875 cleanupDm = true;
876 } else {
877 strcpy(dmDevice, loopDevice);
878 }
879
880 if (mkdir(mountPoint, 0755)) {
881 if (errno != EEXIST) {
882 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
883 if (cleanupDm) {
884 Devmapper::destroy(idHash);
885 }
886 Loop::destroyByDevice(loopDevice);
887 return -1;
888 }
889 }
890
Kenny Roota3e06082010-08-27 08:31:35 -0700891 if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0,
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700892 0227, false)) {
893 SLOGE("Image mount failed (%s)", strerror(errno));
894 if (cleanupDm) {
895 Devmapper::destroy(idHash);
896 }
897 Loop::destroyByDevice(loopDevice);
898 return -1;
899 }
900
Kenny Rootcbacf782010-09-24 15:11:48 -0700901 mActiveContainers->push_back(new ContainerData(strdup(img), OBB));
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700902 if (mDebug) {
903 SLOGD("Image %s mounted", img);
904 }
905 return 0;
906}
907
San Mehat49e2bce2009-10-12 16:29:01 -0700908int VolumeManager::mountVolume(const char *label) {
909 Volume *v = lookupVolume(label);
910
911 if (!v) {
912 errno = ENOENT;
913 return -1;
914 }
915
San Mehata2677e42009-12-13 10:40:18 -0800916 return v->mountVol();
917}
918
Kenny Root508c0e12010-07-12 09:59:49 -0700919int VolumeManager::listMountedObbs(SocketClient* cli) {
920 char device[256];
921 char mount_path[256];
922 char rest[256];
923 FILE *fp;
924 char line[1024];
925
926 if (!(fp = fopen("/proc/mounts", "r"))) {
927 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
928 return -1;
929 }
930
931 // Create a string to compare against that has a trailing slash
932 int loopDirLen = sizeof(Volume::LOOPDIR);
933 char loopDir[loopDirLen + 2];
934 strcpy(loopDir, Volume::LOOPDIR);
935 loopDir[loopDirLen++] = '/';
936 loopDir[loopDirLen] = '\0';
937
938 while(fgets(line, sizeof(line), fp)) {
939 line[strlen(line)-1] = '\0';
940
941 /*
942 * Should look like:
943 * /dev/block/loop0 /mnt/obb/fc99df1323fd36424f864dcb76b76d65 ...
944 */
945 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
946
947 if (!strncmp(mount_path, loopDir, loopDirLen)) {
948 int fd = open(device, O_RDONLY);
949 if (fd >= 0) {
950 struct loop_info64 li;
951 if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
952 cli->sendMsg(ResponseCode::AsecListResult,
953 (const char*) li.lo_file_name, false);
954 }
955 close(fd);
956 }
957 }
958 }
959
960 fclose(fp);
961 return 0;
962}
963
San Mehata2677e42009-12-13 10:40:18 -0800964int VolumeManager::shareAvailable(const char *method, bool *avail) {
965
966 if (strcmp(method, "ums")) {
967 errno = ENOSYS;
968 return -1;
969 }
970
Mike Lockwood99635f62010-06-25 23:04:04 -0400971 *avail = massStorageAvailable();
San Mehata2677e42009-12-13 10:40:18 -0800972 return 0;
973}
974
San Mehateba65e92010-01-29 05:15:16 -0800975int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
976 Volume *v = lookupVolume(label);
977
978 if (!v) {
979 errno = ENOENT;
980 return -1;
981 }
982
983 if (strcmp(method, "ums")) {
984 errno = ENOSYS;
985 return -1;
986 }
987
988 if (v->getState() != Volume::State_Shared) {
San Mehateba65e92010-01-29 05:15:16 -0800989 *enabled = false;
San Mehatb9aed742010-02-04 15:07:01 -0800990 } else {
991 *enabled = true;
San Mehateba65e92010-01-29 05:15:16 -0800992 }
993 return 0;
994}
995
San Mehata2677e42009-12-13 10:40:18 -0800996int VolumeManager::simulate(const char *cmd, const char *arg) {
997
998 if (!strcmp(cmd, "ums")) {
999 if (!strcmp(arg, "connect")) {
Mike Lockwood99635f62010-06-25 23:04:04 -04001000 notifyUmsAvailable(true);
San Mehata2677e42009-12-13 10:40:18 -08001001 } else if (!strcmp(arg, "disconnect")) {
Mike Lockwood99635f62010-06-25 23:04:04 -04001002 notifyUmsAvailable(false);
San Mehata2677e42009-12-13 10:40:18 -08001003 } else {
1004 errno = EINVAL;
1005 return -1;
1006 }
1007 } else {
1008 errno = EINVAL;
1009 return -1;
1010 }
1011 return 0;
1012}
1013
1014int VolumeManager::shareVolume(const char *label, const char *method) {
1015 Volume *v = lookupVolume(label);
1016
1017 if (!v) {
1018 errno = ENOENT;
1019 return -1;
1020 }
1021
1022 /*
1023 * Eventually, we'll want to support additional share back-ends,
1024 * some of which may work while the media is mounted. For now,
1025 * we just support UMS
1026 */
1027 if (strcmp(method, "ums")) {
1028 errno = ENOSYS;
1029 return -1;
1030 }
1031
1032 if (v->getState() == Volume::State_NoMedia) {
1033 errno = ENODEV;
1034 return -1;
1035 }
1036
San Mehat49e2bce2009-10-12 16:29:01 -07001037 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -08001038 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -07001039 errno = EBUSY;
1040 return -1;
1041 }
1042
Mike Lockwood2dfe2972010-09-17 18:50:51 -04001043 dev_t d = v->getShareDevice();
San Mehata2677e42009-12-13 10:40:18 -08001044 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
1045 // This volume does not support raw disk access
1046 errno = EINVAL;
1047 return -1;
1048 }
1049
1050 int fd;
1051 char nodepath[255];
1052 snprintf(nodepath,
1053 sizeof(nodepath), "/dev/block/vold/%d:%d",
1054 MAJOR(d), MINOR(d));
1055
San Mehat0cde53c2009-12-22 08:32:33 -08001056 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file",
1057 O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001058 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001059 return -1;
1060 }
1061
1062 if (write(fd, nodepath, strlen(nodepath)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001063 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001064 close(fd);
1065 return -1;
1066 }
1067
1068 close(fd);
1069 v->handleVolumeShared();
Mike Lockwooda28056b2010-10-28 15:21:24 -04001070 if (mUmsSharingCount++ == 0) {
1071 FILE* fp;
1072 mSavedDirtyRatio = -1; // in case we fail
1073 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1074 char line[16];
1075 if (fgets(line, sizeof(line), fp) && sscanf(line, "%d", &mSavedDirtyRatio)) {
1076 fprintf(fp, "%d\n", mUmsDirtyRatio);
1077 } else {
1078 SLOGE("Failed to read dirty_ratio (%s)", strerror(errno));
1079 }
1080 fclose(fp);
1081 } else {
1082 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1083 }
1084 }
San Mehata2677e42009-12-13 10:40:18 -08001085 return 0;
1086}
1087
1088int VolumeManager::unshareVolume(const char *label, const char *method) {
1089 Volume *v = lookupVolume(label);
1090
1091 if (!v) {
1092 errno = ENOENT;
1093 return -1;
1094 }
1095
1096 if (strcmp(method, "ums")) {
1097 errno = ENOSYS;
1098 return -1;
1099 }
1100
1101 if (v->getState() != Volume::State_Shared) {
1102 errno = EINVAL;
1103 return -1;
1104 }
1105
San Mehata2677e42009-12-13 10:40:18 -08001106 int fd;
San Mehat0cde53c2009-12-22 08:32:33 -08001107 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file", O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001108 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001109 return -1;
1110 }
1111
1112 char ch = 0;
1113 if (write(fd, &ch, 1) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001114 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001115 close(fd);
1116 return -1;
1117 }
1118
1119 close(fd);
1120 v->handleVolumeUnshared();
Mike Lockwooda28056b2010-10-28 15:21:24 -04001121 if (--mUmsSharingCount == 0 && mSavedDirtyRatio != -1) {
1122 FILE* fp;
1123 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1124 fprintf(fp, "%d\n", mSavedDirtyRatio);
1125 fclose(fp);
1126 } else {
1127 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1128 }
1129 mSavedDirtyRatio = -1;
1130 }
San Mehata2677e42009-12-13 10:40:18 -08001131 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -07001132}
1133
Ken Sumrall29d8da82011-05-18 17:20:07 -07001134extern "C" int vold_unmountVol(const char *label) {
1135 VolumeManager *vm = VolumeManager::Instance();
1136 return vm->unmountVolume(label, true);
1137}
1138
1139extern "C" int vold_getNumDirectVolumes(void) {
1140 VolumeManager *vm = VolumeManager::Instance();
1141 return vm->getNumDirectVolumes();
1142}
1143
1144int VolumeManager::getNumDirectVolumes(void) {
1145 VolumeCollection::iterator i;
1146 int n=0;
1147
1148 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1149 if ((*i)->getShareDevice() != (dev_t)0) {
1150 n++;
1151 }
1152 }
1153 return n;
1154}
1155
1156extern "C" int vold_getDirectVolumeList(struct volume_info *vol_list) {
1157 VolumeManager *vm = VolumeManager::Instance();
1158 return vm->getDirectVolumeList(vol_list);
1159}
1160
1161int VolumeManager::getDirectVolumeList(struct volume_info *vol_list) {
1162 VolumeCollection::iterator i;
1163 int n=0;
1164 dev_t d;
1165
1166 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1167 if ((d=(*i)->getShareDevice()) != (dev_t)0) {
1168 (*i)->getVolInfo(&vol_list[n]);
1169 snprintf(vol_list[n].blk_dev, sizeof(vol_list[n].blk_dev),
1170 "/dev/block/vold/%d:%d",MAJOR(d), MINOR(d));
1171 n++;
1172 }
1173 }
1174
1175 return 0;
1176}
1177
San Mehat4ba89482010-02-18 09:00:18 -08001178int VolumeManager::unmountVolume(const char *label, bool force) {
San Mehat49e2bce2009-10-12 16:29:01 -07001179 Volume *v = lookupVolume(label);
1180
1181 if (!v) {
1182 errno = ENOENT;
1183 return -1;
1184 }
1185
San Mehata2677e42009-12-13 10:40:18 -08001186 if (v->getState() == Volume::State_NoMedia) {
1187 errno = ENODEV;
1188 return -1;
1189 }
1190
San Mehat49e2bce2009-10-12 16:29:01 -07001191 if (v->getState() != Volume::State_Mounted) {
San Mehat97ac40e2010-03-24 10:24:19 -07001192 SLOGW("Attempt to unmount volume which isn't mounted (%d)\n",
San Mehata2677e42009-12-13 10:40:18 -08001193 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -07001194 errno = EBUSY;
1195 return -1;
1196 }
1197
San Mehat1a06eda2010-04-15 12:58:50 -07001198 cleanupAsec(v, force);
San Mehat88705162010-01-15 09:26:28 -08001199
San Mehat4ba89482010-02-18 09:00:18 -08001200 return v->unmountVol(force);
San Mehat49e2bce2009-10-12 16:29:01 -07001201}
1202
San Mehata2677e42009-12-13 10:40:18 -08001203/*
1204 * Looks up a volume by it's label or mount-point
1205 */
San Mehat49e2bce2009-10-12 16:29:01 -07001206Volume *VolumeManager::lookupVolume(const char *label) {
1207 VolumeCollection::iterator i;
1208
1209 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -08001210 if (label[0] == '/') {
1211 if (!strcmp(label, (*i)->getMountpoint()))
1212 return (*i);
1213 } else {
1214 if (!strcmp(label, (*i)->getLabel()))
1215 return (*i);
1216 }
San Mehat49e2bce2009-10-12 16:29:01 -07001217 }
1218 return NULL;
1219}
San Mehata19b2502010-01-06 10:33:53 -08001220
1221bool VolumeManager::isMountpointMounted(const char *mp)
1222{
1223 char device[256];
1224 char mount_path[256];
1225 char rest[256];
1226 FILE *fp;
1227 char line[1024];
1228
1229 if (!(fp = fopen("/proc/mounts", "r"))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001230 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001231 return false;
1232 }
1233
1234 while(fgets(line, sizeof(line), fp)) {
1235 line[strlen(line)-1] = '\0';
1236 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1237 if (!strcmp(mount_path, mp)) {
1238 fclose(fp);
1239 return true;
1240 }
San Mehata19b2502010-01-06 10:33:53 -08001241 }
1242
1243 fclose(fp);
1244 return false;
1245}
1246
San Mehat1a06eda2010-04-15 12:58:50 -07001247int VolumeManager::cleanupAsec(Volume *v, bool force) {
1248 while(mActiveContainers->size()) {
1249 AsecIdCollection::iterator it = mActiveContainers->begin();
Kenny Rootcbacf782010-09-24 15:11:48 -07001250 ContainerData* cd = *it;
1251 SLOGI("Unmounting ASEC %s (dependant on %s)", cd->id, v->getMountpoint());
1252 if (cd->type == ASEC) {
1253 if (unmountAsec(cd->id, force)) {
1254 SLOGE("Failed to unmount ASEC %s (%s)", cd->id, strerror(errno));
1255 return -1;
1256 }
1257 } else if (cd->type == OBB) {
1258 if (unmountObb(cd->id, force)) {
1259 SLOGE("Failed to unmount OBB %s (%s)", cd->id, strerror(errno));
1260 return -1;
1261 }
1262 } else {
1263 SLOGE("Unknown container type %d!", cd->type);
San Mehat1a06eda2010-04-15 12:58:50 -07001264 return -1;
1265 }
1266 }
1267 return 0;
1268}
1269