blob: 3b229b7a5dadcdd23ccd816190982207b2da2ef5 [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;
60
61 readInitialState();
62}
63
64void VolumeManager::readInitialState() {
65 FILE *fp;
66 char state[255];
67
68 /*
69 * Read the initial mass storage enabled state
70 */
71 if ((fp = fopen("/sys/devices/virtual/usb_composite/usb_mass_storage/enable", "r"))) {
72 if (fgets(state, sizeof(state), fp)) {
73 mUsbMassStorageEnabled = !strncmp(state, "1", 1);
74 } else {
75 SLOGE("Failed to read usb_mass_storage enabled state (%s)", strerror(errno));
76 }
77 fclose(fp);
78 } else {
79 SLOGD("USB mass storage support is not enabled in the kernel");
80 }
81
82 /*
83 * Read the initial USB connected state
84 */
85 if ((fp = fopen("/sys/devices/virtual/switch/usb_configuration/state", "r"))) {
86 if (fgets(state, sizeof(state), fp)) {
87 mUsbConnected = !strncmp(state, "1", 1);
88 } else {
89 SLOGE("Failed to read usb_configuration switch (%s)", strerror(errno));
90 }
91 fclose(fp);
92 } else {
93 SLOGD("usb_configuration switch is not enabled in the kernel");
94 }
San Mehatf1b736b2009-10-10 17:22:08 -070095}
96
97VolumeManager::~VolumeManager() {
San Mehat88705162010-01-15 09:26:28 -080098 delete mVolumes;
99 delete mActiveContainers;
San Mehatf1b736b2009-10-10 17:22:08 -0700100}
101
Kenny Root7b18a7b2010-03-15 13:13:41 -0700102char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700103 static const char* digits = "0123456789abcdef";
104
Kenny Root7b18a7b2010-03-15 13:13:41 -0700105 unsigned char sig[MD5_DIGEST_LENGTH];
106
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700107 if (buffer == NULL) {
108 SLOGE("Destination buffer is NULL");
109 errno = ESPIPE;
110 return NULL;
111 } else if (id == NULL) {
112 SLOGE("Source buffer is NULL");
113 errno = ESPIPE;
114 return NULL;
115 } else if (len < MD5_ASCII_LENGTH_PLUS_NULL) {
116 SLOGE("Target hash buffer size < %d bytes (%d)",
117 MD5_ASCII_LENGTH_PLUS_NULL, len);
San Mehatd9a4e352010-03-12 13:32:47 -0800118 errno = ESPIPE;
119 return NULL;
120 }
Kenny Root7b18a7b2010-03-15 13:13:41 -0700121
122 MD5(reinterpret_cast<const unsigned char*>(id), strlen(id), sig);
San Mehatd9a4e352010-03-12 13:32:47 -0800123
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700124 char *p = buffer;
Kenny Root7b18a7b2010-03-15 13:13:41 -0700125 for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700126 *p++ = digits[sig[i] >> 4];
127 *p++ = digits[sig[i] & 0x0F];
San Mehatd9a4e352010-03-12 13:32:47 -0800128 }
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700129 *p = '\0';
San Mehatd9a4e352010-03-12 13:32:47 -0800130
131 return buffer;
132}
133
134void VolumeManager::setDebug(bool enable) {
135 mDebug = enable;
136 VolumeCollection::iterator it;
137 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
138 (*it)->setDebug(enable);
139 }
140}
141
San Mehatf1b736b2009-10-10 17:22:08 -0700142int VolumeManager::start() {
143 return 0;
144}
145
146int VolumeManager::stop() {
147 return 0;
148}
149
150int VolumeManager::addVolume(Volume *v) {
151 mVolumes->push_back(v);
152 return 0;
153}
154
Mike Lockwood99635f62010-06-25 23:04:04 -0400155void VolumeManager::notifyUmsAvailable(bool available) {
San Mehata2677e42009-12-13 10:40:18 -0800156 char msg[255];
157
San Mehata2677e42009-12-13 10:40:18 -0800158 snprintf(msg, sizeof(msg), "Share method ums now %s",
Mike Lockwood99635f62010-06-25 23:04:04 -0400159 (available ? "available" : "unavailable"));
160 SLOGD(msg);
San Mehata2677e42009-12-13 10:40:18 -0800161 getBroadcaster()->sendBroadcast(ResponseCode::ShareAvailabilityChange,
162 msg, false);
163}
164
165void VolumeManager::handleSwitchEvent(NetlinkEvent *evt) {
San Mehat0cde53c2009-12-22 08:32:33 -0800166 const char *devpath = evt->findParam("DEVPATH");
San Mehata2677e42009-12-13 10:40:18 -0800167 const char *name = evt->findParam("SWITCH_NAME");
168 const char *state = evt->findParam("SWITCH_STATE");
169
San Mehat0cde53c2009-12-22 08:32:33 -0800170 if (!name || !state) {
San Mehat97ac40e2010-03-24 10:24:19 -0700171 SLOGW("Switch %s event missing name/state info", devpath);
San Mehat0cde53c2009-12-22 08:32:33 -0800172 return;
173 }
174
Mike Lockwood99635f62010-06-25 23:04:04 -0400175 bool oldAvailable = massStorageAvailable();
176 if (!strcmp(name, "usb_configuration")) {
177 mUsbConnected = !strcmp(state, "1");
178 SLOGD("USB %s", mUsbConnected ? "connected" : "disconnected");
179 bool newAvailable = massStorageAvailable();
180 if (newAvailable != oldAvailable) {
181 notifyUmsAvailable(newAvailable);
San Mehata2677e42009-12-13 10:40:18 -0800182 }
183 } else {
San Mehat97ac40e2010-03-24 10:24:19 -0700184 SLOGW("Ignoring unknown switch '%s'", name);
San Mehata2677e42009-12-13 10:40:18 -0800185 }
186}
Mike Lockwood99635f62010-06-25 23:04:04 -0400187void VolumeManager::handleUsbCompositeEvent(NetlinkEvent *evt) {
188 const char *function = evt->findParam("FUNCTION");
189 const char *enabled = evt->findParam("ENABLED");
190
191 if (!function || !enabled) {
192 SLOGW("usb_composite event missing function/enabled info");
193 return;
194 }
195
196 if (!strcmp(function, "usb_mass_storage")) {
197 bool oldAvailable = massStorageAvailable();
198 mUsbMassStorageEnabled = !strcmp(enabled, "1");
199 SLOGD("usb_mass_storage function %s", mUsbMassStorageEnabled ? "enabled" : "disabled");
200 bool newAvailable = massStorageAvailable();
201 if (newAvailable != oldAvailable) {
202 notifyUmsAvailable(newAvailable);
203 }
204 }
205}
San Mehata2677e42009-12-13 10:40:18 -0800206
San Mehatfd7f5872009-10-12 11:32:47 -0700207void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
208 const char *devpath = evt->findParam("DEVPATH");
San Mehatf1b736b2009-10-10 17:22:08 -0700209
San Mehatfd7f5872009-10-12 11:32:47 -0700210 /* Lookup a volume to handle this device */
San Mehatf1b736b2009-10-10 17:22:08 -0700211 VolumeCollection::iterator it;
212 bool hit = false;
213 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
San Mehatfd7f5872009-10-12 11:32:47 -0700214 if (!(*it)->handleBlockEvent(evt)) {
San Mehata2677e42009-12-13 10:40:18 -0800215#ifdef NETLINK_DEBUG
San Mehat97ac40e2010-03-24 10:24:19 -0700216 SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
San Mehata2677e42009-12-13 10:40:18 -0800217#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700218 hit = true;
San Mehatf1b736b2009-10-10 17:22:08 -0700219 break;
220 }
221 }
222
223 if (!hit) {
San Mehata2677e42009-12-13 10:40:18 -0800224#ifdef NETLINK_DEBUG
San Mehat97ac40e2010-03-24 10:24:19 -0700225 SLOGW("No volumes handled block event for '%s'", devpath);
San Mehata2677e42009-12-13 10:40:18 -0800226#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700227 }
228}
229
San Mehatf1b736b2009-10-10 17:22:08 -0700230int VolumeManager::listVolumes(SocketClient *cli) {
231 VolumeCollection::iterator i;
232
233 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
234 char *buffer;
235 asprintf(&buffer, "%s %s %d",
236 (*i)->getLabel(), (*i)->getMountpoint(),
237 (*i)->getState());
San Mehata2677e42009-12-13 10:40:18 -0800238 cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
San Mehatf1b736b2009-10-10 17:22:08 -0700239 free(buffer);
240 }
San Mehata2677e42009-12-13 10:40:18 -0800241 cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
San Mehatf1b736b2009-10-10 17:22:08 -0700242 return 0;
243}
San Mehat49e2bce2009-10-12 16:29:01 -0700244
San Mehata2677e42009-12-13 10:40:18 -0800245int VolumeManager::formatVolume(const char *label) {
246 Volume *v = lookupVolume(label);
247
248 if (!v) {
249 errno = ENOENT;
250 return -1;
251 }
252
253 return v->formatVol();
254}
255
Kenny Root508c0e12010-07-12 09:59:49 -0700256int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) {
257 char idHash[33];
258 if (!asecHash(sourceFile, idHash, sizeof(idHash))) {
259 SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno));
260 return -1;
261 }
262
263 memset(mountPath, 0, mountPathLen);
264 snprintf(mountPath, mountPathLen, "%s/%s", Volume::LOOPDIR, idHash);
265
266 if (access(mountPath, F_OK)) {
267 errno = ENOENT;
268 return -1;
269 }
270
271 return 0;
272}
273
San Mehata19b2502010-01-06 10:33:53 -0800274int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
San Mehat88ac2c02010-03-23 11:15:58 -0700275 char asecFileName[255];
276 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
277
278 memset(buffer, 0, maxlen);
279 if (access(asecFileName, F_OK)) {
280 errno = ENOENT;
281 return -1;
282 }
San Mehata19b2502010-01-06 10:33:53 -0800283
San Mehat3bb60202010-02-19 18:14:36 -0800284 snprintf(buffer, maxlen, "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800285 return 0;
286}
287
San Mehat8b8f71b2010-01-11 09:17:25 -0800288int VolumeManager::createAsec(const char *id, unsigned int numSectors,
San Mehata19b2502010-01-06 10:33:53 -0800289 const char *fstype, const char *key, int ownerUid) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800290 struct asec_superblock sb;
291 memset(&sb, 0, sizeof(sb));
292
293 sb.magic = ASEC_SB_MAGIC;
294 sb.ver = ASEC_SB_VER;
San Mehata19b2502010-01-06 10:33:53 -0800295
San Mehatd31e3802010-02-18 08:37:45 -0800296 if (numSectors < ((1024*1024)/512)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700297 SLOGE("Invalid container size specified (%d sectors)", numSectors);
San Mehatd31e3802010-02-18 08:37:45 -0800298 errno = EINVAL;
299 return -1;
300 }
301
San Mehata19b2502010-01-06 10:33:53 -0800302 if (lookupVolume(id)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700303 SLOGE("ASEC id '%s' currently exists", id);
San Mehata19b2502010-01-06 10:33:53 -0800304 errno = EADDRINUSE;
305 return -1;
306 }
307
308 char asecFileName[255];
San Mehat3bb60202010-02-19 18:14:36 -0800309 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800310
311 if (!access(asecFileName, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700312 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
San Mehata19b2502010-01-06 10:33:53 -0800313 asecFileName, strerror(errno));
314 errno = EADDRINUSE;
315 return -1;
316 }
317
San Mehatfcf24fe2010-03-03 12:37:32 -0800318 /*
319 * Add some headroom
320 */
321 unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
322 unsigned numImgSectors = numSectors + fatSize + 2;
323
324 if (numImgSectors % 63) {
325 numImgSectors += (63 - (numImgSectors % 63));
326 }
327
328 // Add +1 for our superblock which is at the end
329 if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700330 SLOGE("ASEC image file creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800331 return -1;
332 }
333
San Mehatd9a4e352010-03-12 13:32:47 -0800334 char idHash[33];
335 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700336 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800337 unlink(asecFileName);
338 return -1;
339 }
340
San Mehata19b2502010-01-06 10:33:53 -0800341 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800342 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700343 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800344 unlink(asecFileName);
345 return -1;
346 }
347
San Mehatb78a32c2010-01-10 13:02:12 -0800348 char dmDevice[255];
349 bool cleanupDm = false;
San Mehata19b2502010-01-06 10:33:53 -0800350
San Mehatb78a32c2010-01-10 13:02:12 -0800351 if (strcmp(key, "none")) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800352 // XXX: This is all we support for now
353 sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
San Mehatd9a4e352010-03-12 13:32:47 -0800354 if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
San Mehatb78a32c2010-01-10 13:02:12 -0800355 sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700356 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800357 Loop::destroyByDevice(loopDevice);
358 unlink(asecFileName);
359 return -1;
360 }
361 cleanupDm = true;
362 } else {
San Mehatfcf24fe2010-03-03 12:37:32 -0800363 sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
San Mehatb78a32c2010-01-10 13:02:12 -0800364 strcpy(dmDevice, loopDevice);
365 }
366
San Mehatfcf24fe2010-03-03 12:37:32 -0800367 /*
368 * Drop down the superblock at the end of the file
369 */
370
371 int sbfd = open(loopDevice, O_RDWR);
372 if (sbfd < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700373 SLOGE("Failed to open new DM device for superblock write (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800374 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800375 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800376 }
377 Loop::destroyByDevice(loopDevice);
378 unlink(asecFileName);
379 return -1;
380 }
381
382 if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
383 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700384 SLOGE("Failed to lseek for superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800385 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800386 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800387 }
388 Loop::destroyByDevice(loopDevice);
389 unlink(asecFileName);
390 return -1;
391 }
392
393 if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) {
394 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700395 SLOGE("Failed to write superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800396 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800397 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800398 }
399 Loop::destroyByDevice(loopDevice);
400 unlink(asecFileName);
401 return -1;
402 }
403 close(sbfd);
404
San Mehata1091cb2010-02-28 20:17:20 -0800405 if (strcmp(fstype, "none")) {
406 if (strcmp(fstype, "fat")) {
San Mehat97ac40e2010-03-24 10:24:19 -0700407 SLOGW("Unknown fstype '%s' specified for container", fstype);
San Mehatb78a32c2010-01-10 13:02:12 -0800408 }
San Mehata19b2502010-01-06 10:33:53 -0800409
San Mehatfcf24fe2010-03-03 12:37:32 -0800410 if (Fat::format(dmDevice, numImgSectors)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700411 SLOGE("ASEC FAT format failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800412 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800413 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800414 }
San Mehateb13a902010-01-07 12:12:50 -0800415 Loop::destroyByDevice(loopDevice);
416 unlink(asecFileName);
417 return -1;
418 }
San Mehata1091cb2010-02-28 20:17:20 -0800419 char mountPoint[255];
San Mehata19b2502010-01-06 10:33:53 -0800420
San Mehata1091cb2010-02-28 20:17:20 -0800421 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
422 if (mkdir(mountPoint, 0777)) {
423 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -0700424 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800425 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800426 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800427 }
428 Loop::destroyByDevice(loopDevice);
429 unlink(asecFileName);
430 return -1;
431 }
San Mehatb78a32c2010-01-10 13:02:12 -0800432 }
San Mehata1091cb2010-02-28 20:17:20 -0800433
Kenny Roota3e06082010-08-27 08:31:35 -0700434 if (Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid,
San Mehata1091cb2010-02-28 20:17:20 -0800435 0, 0000, false)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700436 SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800437 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800438 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800439 }
440 Loop::destroyByDevice(loopDevice);
441 unlink(asecFileName);
442 return -1;
443 }
444 } else {
San Mehat97ac40e2010-03-24 10:24:19 -0700445 SLOGI("Created raw secure container %s (no filesystem)", id);
San Mehata19b2502010-01-06 10:33:53 -0800446 }
San Mehat88705162010-01-15 09:26:28 -0800447
Kenny Rootcbacf782010-09-24 15:11:48 -0700448 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehata19b2502010-01-06 10:33:53 -0800449 return 0;
450}
451
452int VolumeManager::finalizeAsec(const char *id) {
453 char asecFileName[255];
454 char loopDevice[255];
455 char mountPoint[255];
456
San Mehat3bb60202010-02-19 18:14:36 -0800457 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800458
San Mehatd9a4e352010-03-12 13:32:47 -0800459 char idHash[33];
460 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700461 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800462 return -1;
463 }
464
465 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700466 SLOGE("Unable to finalize %s (%s)", id, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800467 return -1;
468 }
469
San Mehat3bb60202010-02-19 18:14:36 -0800470 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatfff0b472010-01-06 19:19:46 -0800471 // XXX:
Kenny Roota3e06082010-08-27 08:31:35 -0700472 if (Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700473 SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800474 return -1;
475 }
476
San Mehatd9a4e352010-03-12 13:32:47 -0800477 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700478 SLOGD("ASEC %s finalized", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800479 }
San Mehata19b2502010-01-06 10:33:53 -0800480 return 0;
481}
482
San Mehat048b0802010-01-23 08:17:06 -0800483int VolumeManager::renameAsec(const char *id1, const char *id2) {
484 char *asecFilename1;
485 char *asecFilename2;
486 char mountPoint[255];
487
San Mehat3bb60202010-02-19 18:14:36 -0800488 asprintf(&asecFilename1, "%s/%s.asec", Volume::SEC_ASECDIR, id1);
489 asprintf(&asecFilename2, "%s/%s.asec", Volume::SEC_ASECDIR, id2);
San Mehat048b0802010-01-23 08:17:06 -0800490
San Mehat3bb60202010-02-19 18:14:36 -0800491 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
San Mehat048b0802010-01-23 08:17:06 -0800492 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700493 SLOGW("Rename attempt when src mounted");
San Mehat048b0802010-01-23 08:17:06 -0800494 errno = EBUSY;
495 goto out_err;
496 }
497
San Mehat96956ed2010-02-24 08:42:51 -0800498 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2);
499 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700500 SLOGW("Rename attempt when dst mounted");
San Mehat96956ed2010-02-24 08:42:51 -0800501 errno = EBUSY;
502 goto out_err;
503 }
504
San Mehat048b0802010-01-23 08:17:06 -0800505 if (!access(asecFilename2, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700506 SLOGE("Rename attempt when dst exists");
San Mehat048b0802010-01-23 08:17:06 -0800507 errno = EADDRINUSE;
508 goto out_err;
509 }
510
511 if (rename(asecFilename1, asecFilename2)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700512 SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
San Mehat048b0802010-01-23 08:17:06 -0800513 goto out_err;
514 }
515
516 free(asecFilename1);
517 free(asecFilename2);
518 return 0;
519
520out_err:
521 free(asecFilename1);
522 free(asecFilename2);
523 return -1;
524}
525
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700526#define UNMOUNT_RETRIES 5
527#define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
San Mehat4ba89482010-02-18 09:00:18 -0800528int VolumeManager::unmountAsec(const char *id, bool force) {
San Mehata19b2502010-01-06 10:33:53 -0800529 char asecFileName[255];
530 char mountPoint[255];
531
San Mehat3bb60202010-02-19 18:14:36 -0800532 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
533 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800534
San Mehatd9a4e352010-03-12 13:32:47 -0800535 char idHash[33];
536 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700537 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800538 return -1;
539 }
540
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700541 return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
542}
543
Kenny Root508c0e12010-07-12 09:59:49 -0700544int VolumeManager::unmountObb(const char *fileName, bool force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700545 char mountPoint[255];
546
547 char idHash[33];
548 if (!asecHash(fileName, idHash, sizeof(idHash))) {
549 SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
550 return -1;
551 }
552
553 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
554
555 return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
556}
557
558int VolumeManager::unmountLoopImage(const char *id, const char *idHash,
559 const char *fileName, const char *mountPoint, bool force) {
San Mehat0586d542010-01-12 15:38:59 -0800560 if (!isMountpointMounted(mountPoint)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700561 SLOGE("Unmount request for %s when not mounted", id);
Kenny Root918e5f92010-09-30 18:00:52 -0700562 errno = ENOENT;
San Mehatb78a32c2010-01-10 13:02:12 -0800563 return -1;
564 }
San Mehat23969932010-01-09 07:08:06 -0800565
San Mehatb78a32c2010-01-10 13:02:12 -0800566 int i, rc;
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700567 for (i = 1; i <= UNMOUNT_RETRIES; i++) {
San Mehatb78a32c2010-01-10 13:02:12 -0800568 rc = umount(mountPoint);
569 if (!rc) {
570 break;
San Mehata19b2502010-01-06 10:33:53 -0800571 }
San Mehatb78a32c2010-01-10 13:02:12 -0800572 if (rc && (errno == EINVAL || errno == ENOENT)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700573 SLOGI("Container %s unmounted OK", id);
San Mehatb78a32c2010-01-10 13:02:12 -0800574 rc = 0;
575 break;
San Mehata19b2502010-01-06 10:33:53 -0800576 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700577 SLOGW("%s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -0800578 id, i, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800579
San Mehat4ba89482010-02-18 09:00:18 -0800580 int action = 0; // default is to just complain
581
582 if (force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700583 if (i > (UNMOUNT_RETRIES - 2))
San Mehat4ba89482010-02-18 09:00:18 -0800584 action = 2; // SIGKILL
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700585 else if (i > (UNMOUNT_RETRIES - 3))
San Mehat4ba89482010-02-18 09:00:18 -0800586 action = 1; // SIGHUP
587 }
San Mehat8c940ef2010-02-13 14:19:53 -0800588
San Mehat586536c2010-02-16 17:12:00 -0800589 Process::killProcessesWithOpenFiles(mountPoint, action);
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700590 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehatb78a32c2010-01-10 13:02:12 -0800591 }
592
593 if (rc) {
San Mehat4ba89482010-02-18 09:00:18 -0800594 errno = EBUSY;
San Mehat97ac40e2010-03-24 10:24:19 -0700595 SLOGE("Failed to unmount container %s (%s)", id, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800596 return -1;
597 }
598
San Mehat12f4b892010-02-24 11:43:22 -0800599 int retries = 10;
600
601 while(retries--) {
602 if (!rmdir(mountPoint)) {
603 break;
604 }
605
San Mehat97ac40e2010-03-24 10:24:19 -0700606 SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700607 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehat12f4b892010-02-24 11:43:22 -0800608 }
609
610 if (!retries) {
San Mehat97ac40e2010-03-24 10:24:19 -0700611 SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
San Mehatf5c61982010-02-03 11:04:46 -0800612 }
San Mehat88705162010-01-15 09:26:28 -0800613
San Mehatd9a4e352010-03-12 13:32:47 -0800614 if (Devmapper::destroy(idHash) && errno != ENXIO) {
San Mehat97ac40e2010-03-24 10:24:19 -0700615 SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800616 }
617
618 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800619 if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800620 Loop::destroyByDevice(loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800621 } else {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700622 SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800623 }
San Mehat88705162010-01-15 09:26:28 -0800624
625 AsecIdCollection::iterator it;
626 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
Kenny Rootcbacf782010-09-24 15:11:48 -0700627 ContainerData* cd = *it;
628 if (!strcmp(cd->id, id)) {
San Mehat88705162010-01-15 09:26:28 -0800629 free(*it);
630 mActiveContainers->erase(it);
631 break;
632 }
633 }
634 if (it == mActiveContainers->end()) {
San Mehat97ac40e2010-03-24 10:24:19 -0700635 SLOGW("mActiveContainers is inconsistent!");
San Mehat88705162010-01-15 09:26:28 -0800636 }
San Mehatb78a32c2010-01-10 13:02:12 -0800637 return 0;
638}
639
San Mehat4ba89482010-02-18 09:00:18 -0800640int VolumeManager::destroyAsec(const char *id, bool force) {
San Mehatb78a32c2010-01-10 13:02:12 -0800641 char asecFileName[255];
642 char mountPoint[255];
643
San Mehat3bb60202010-02-19 18:14:36 -0800644 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehat55013f72010-02-24 12:12:34 -0800645 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatb78a32c2010-01-10 13:02:12 -0800646
San Mehat0586d542010-01-12 15:38:59 -0800647 if (isMountpointMounted(mountPoint)) {
San Mehatd9a4e352010-03-12 13:32:47 -0800648 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700649 SLOGD("Unmounting container before destroy");
San Mehatd9a4e352010-03-12 13:32:47 -0800650 }
San Mehat4ba89482010-02-18 09:00:18 -0800651 if (unmountAsec(id, force)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700652 SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800653 return -1;
654 }
655 }
San Mehata19b2502010-01-06 10:33:53 -0800656
San Mehat0586d542010-01-12 15:38:59 -0800657 if (unlink(asecFileName)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700658 SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800659 return -1;
660 }
San Mehata19b2502010-01-06 10:33:53 -0800661
San Mehatd9a4e352010-03-12 13:32:47 -0800662 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700663 SLOGD("ASEC %s destroyed", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800664 }
San Mehata19b2502010-01-06 10:33:53 -0800665 return 0;
666}
667
668int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
669 char asecFileName[255];
670 char mountPoint[255];
671
San Mehat3bb60202010-02-19 18:14:36 -0800672 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
673 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800674
675 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700676 SLOGE("ASEC %s already mounted", id);
San Mehata19b2502010-01-06 10:33:53 -0800677 errno = EBUSY;
678 return -1;
679 }
680
San Mehatd9a4e352010-03-12 13:32:47 -0800681 char idHash[33];
682 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700683 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800684 return -1;
685 }
Kenny Root7b18a7b2010-03-15 13:13:41 -0700686
San Mehata19b2502010-01-06 10:33:53 -0800687 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800688 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
689 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700690 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800691 return -1;
692 }
San Mehatd9a4e352010-03-12 13:32:47 -0800693 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700694 SLOGD("New loop device created at %s", loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800695 }
San Mehatb78a32c2010-01-10 13:02:12 -0800696 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800697 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700698 SLOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800699 }
San Mehatb78a32c2010-01-10 13:02:12 -0800700 }
701
702 char dmDevice[255];
703 bool cleanupDm = false;
San Mehatfcf24fe2010-03-03 12:37:32 -0800704 int fd;
705 unsigned int nr_sec = 0;
706
707 if ((fd = open(loopDevice, O_RDWR)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700708 SLOGE("Failed to open loopdevice (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800709 Loop::destroyByDevice(loopDevice);
710 return -1;
711 }
712
713 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700714 SLOGE("Failed to get loop size (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800715 Loop::destroyByDevice(loopDevice);
716 close(fd);
717 return -1;
718 }
719
720 /*
721 * Validate superblock
722 */
723 struct asec_superblock sb;
724 memset(&sb, 0, sizeof(sb));
725 if (lseek(fd, ((nr_sec-1) * 512), SEEK_SET) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700726 SLOGE("lseek failed (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800727 close(fd);
728 Loop::destroyByDevice(loopDevice);
729 return -1;
730 }
731 if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700732 SLOGE("superblock read failed (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800733 close(fd);
734 Loop::destroyByDevice(loopDevice);
735 return -1;
736 }
737
738 close(fd);
739
San Mehatd9a4e352010-03-12 13:32:47 -0800740 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700741 SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatd9a4e352010-03-12 13:32:47 -0800742 }
San Mehatfcf24fe2010-03-03 12:37:32 -0800743 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
San Mehat97ac40e2010-03-24 10:24:19 -0700744 SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatfcf24fe2010-03-03 12:37:32 -0800745 Loop::destroyByDevice(loopDevice);
746 errno = EMEDIUMTYPE;
747 return -1;
748 }
749 nr_sec--; // We don't want the devmapping to extend onto our superblock
750
San Mehatb78a32c2010-01-10 13:02:12 -0800751 if (strcmp(key, "none")) {
San Mehatd9a4e352010-03-12 13:32:47 -0800752 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
753 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
San Mehatb78a32c2010-01-10 13:02:12 -0800754 dmDevice, sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700755 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800756 Loop::destroyByDevice(loopDevice);
757 return -1;
758 }
San Mehatd9a4e352010-03-12 13:32:47 -0800759 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700760 SLOGD("New devmapper instance created at %s", dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800761 }
San Mehatb78a32c2010-01-10 13:02:12 -0800762 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800763 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700764 SLOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800765 }
San Mehatb78a32c2010-01-10 13:02:12 -0800766 }
767 cleanupDm = true;
768 } else {
769 strcpy(dmDevice, loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800770 }
771
772 if (mkdir(mountPoint, 0777)) {
San Mehatb78a32c2010-01-10 13:02:12 -0800773 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -0700774 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800775 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800776 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800777 }
778 Loop::destroyByDevice(loopDevice);
779 return -1;
780 }
San Mehata19b2502010-01-06 10:33:53 -0800781 }
782
Kenny Roota3e06082010-08-27 08:31:35 -0700783 if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0,
San Mehatcff5ec32010-01-08 12:31:44 -0800784 0222, false)) {
785// 0227, false)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700786 SLOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800787 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800788 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800789 }
790 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800791 return -1;
792 }
793
Kenny Rootcbacf782010-09-24 15:11:48 -0700794 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehatd9a4e352010-03-12 13:32:47 -0800795 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700796 SLOGD("ASEC %s mounted", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800797 }
San Mehata19b2502010-01-06 10:33:53 -0800798 return 0;
799}
800
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700801/**
802 * Mounts an image file <code>img</code>.
803 */
Kenny Root508c0e12010-07-12 09:59:49 -0700804int VolumeManager::mountObb(const char *img, const char *key, int ownerUid) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700805 char mountPoint[255];
806
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700807 char idHash[33];
808 if (!asecHash(img, idHash, sizeof(idHash))) {
809 SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
810 return -1;
811 }
812
813 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
814
815 if (isMountpointMounted(mountPoint)) {
816 SLOGE("Image %s already mounted", img);
817 errno = EBUSY;
818 return -1;
819 }
820
821 char loopDevice[255];
822 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
823 if (Loop::create(idHash, img, loopDevice, sizeof(loopDevice))) {
824 SLOGE("Image loop device creation failed (%s)", strerror(errno));
825 return -1;
826 }
827 if (mDebug) {
828 SLOGD("New loop device created at %s", loopDevice);
829 }
830 } else {
831 if (mDebug) {
832 SLOGD("Found active loopback for %s at %s", img, loopDevice);
833 }
834 }
835
836 char dmDevice[255];
837 bool cleanupDm = false;
838 int fd;
839 unsigned int nr_sec = 0;
840
841 if ((fd = open(loopDevice, O_RDWR)) < 0) {
842 SLOGE("Failed to open loopdevice (%s)", strerror(errno));
843 Loop::destroyByDevice(loopDevice);
844 return -1;
845 }
846
847 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
848 SLOGE("Failed to get loop size (%s)", strerror(errno));
849 Loop::destroyByDevice(loopDevice);
850 close(fd);
851 return -1;
852 }
853
854 close(fd);
855
856 if (strcmp(key, "none")) {
857 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
858 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
859 dmDevice, sizeof(dmDevice))) {
860 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
861 Loop::destroyByDevice(loopDevice);
862 return -1;
863 }
864 if (mDebug) {
865 SLOGD("New devmapper instance created at %s", dmDevice);
866 }
867 } else {
868 if (mDebug) {
869 SLOGD("Found active devmapper for %s at %s", img, dmDevice);
870 }
871 }
872 cleanupDm = true;
873 } else {
874 strcpy(dmDevice, loopDevice);
875 }
876
877 if (mkdir(mountPoint, 0755)) {
878 if (errno != EEXIST) {
879 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
880 if (cleanupDm) {
881 Devmapper::destroy(idHash);
882 }
883 Loop::destroyByDevice(loopDevice);
884 return -1;
885 }
886 }
887
Kenny Roota3e06082010-08-27 08:31:35 -0700888 if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0,
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700889 0227, false)) {
890 SLOGE("Image mount failed (%s)", strerror(errno));
891 if (cleanupDm) {
892 Devmapper::destroy(idHash);
893 }
894 Loop::destroyByDevice(loopDevice);
895 return -1;
896 }
897
Kenny Rootcbacf782010-09-24 15:11:48 -0700898 mActiveContainers->push_back(new ContainerData(strdup(img), OBB));
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700899 if (mDebug) {
900 SLOGD("Image %s mounted", img);
901 }
902 return 0;
903}
904
San Mehat49e2bce2009-10-12 16:29:01 -0700905int VolumeManager::mountVolume(const char *label) {
906 Volume *v = lookupVolume(label);
907
908 if (!v) {
909 errno = ENOENT;
910 return -1;
911 }
912
San Mehata2677e42009-12-13 10:40:18 -0800913 return v->mountVol();
914}
915
Kenny Root508c0e12010-07-12 09:59:49 -0700916int VolumeManager::listMountedObbs(SocketClient* cli) {
917 char device[256];
918 char mount_path[256];
919 char rest[256];
920 FILE *fp;
921 char line[1024];
922
923 if (!(fp = fopen("/proc/mounts", "r"))) {
924 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
925 return -1;
926 }
927
928 // Create a string to compare against that has a trailing slash
929 int loopDirLen = sizeof(Volume::LOOPDIR);
930 char loopDir[loopDirLen + 2];
931 strcpy(loopDir, Volume::LOOPDIR);
932 loopDir[loopDirLen++] = '/';
933 loopDir[loopDirLen] = '\0';
934
935 while(fgets(line, sizeof(line), fp)) {
936 line[strlen(line)-1] = '\0';
937
938 /*
939 * Should look like:
940 * /dev/block/loop0 /mnt/obb/fc99df1323fd36424f864dcb76b76d65 ...
941 */
942 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
943
944 if (!strncmp(mount_path, loopDir, loopDirLen)) {
945 int fd = open(device, O_RDONLY);
946 if (fd >= 0) {
947 struct loop_info64 li;
948 if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
949 cli->sendMsg(ResponseCode::AsecListResult,
950 (const char*) li.lo_file_name, false);
951 }
952 close(fd);
953 }
954 }
955 }
956
957 fclose(fp);
958 return 0;
959}
960
San Mehata2677e42009-12-13 10:40:18 -0800961int VolumeManager::shareAvailable(const char *method, bool *avail) {
962
963 if (strcmp(method, "ums")) {
964 errno = ENOSYS;
965 return -1;
966 }
967
Mike Lockwood99635f62010-06-25 23:04:04 -0400968 *avail = massStorageAvailable();
San Mehata2677e42009-12-13 10:40:18 -0800969 return 0;
970}
971
San Mehateba65e92010-01-29 05:15:16 -0800972int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
973 Volume *v = lookupVolume(label);
974
975 if (!v) {
976 errno = ENOENT;
977 return -1;
978 }
979
980 if (strcmp(method, "ums")) {
981 errno = ENOSYS;
982 return -1;
983 }
984
985 if (v->getState() != Volume::State_Shared) {
San Mehateba65e92010-01-29 05:15:16 -0800986 *enabled = false;
San Mehatb9aed742010-02-04 15:07:01 -0800987 } else {
988 *enabled = true;
San Mehateba65e92010-01-29 05:15:16 -0800989 }
990 return 0;
991}
992
San Mehata2677e42009-12-13 10:40:18 -0800993int VolumeManager::simulate(const char *cmd, const char *arg) {
994
995 if (!strcmp(cmd, "ums")) {
996 if (!strcmp(arg, "connect")) {
Mike Lockwood99635f62010-06-25 23:04:04 -0400997 notifyUmsAvailable(true);
San Mehata2677e42009-12-13 10:40:18 -0800998 } else if (!strcmp(arg, "disconnect")) {
Mike Lockwood99635f62010-06-25 23:04:04 -0400999 notifyUmsAvailable(false);
San Mehata2677e42009-12-13 10:40:18 -08001000 } else {
1001 errno = EINVAL;
1002 return -1;
1003 }
1004 } else {
1005 errno = EINVAL;
1006 return -1;
1007 }
1008 return 0;
1009}
1010
1011int VolumeManager::shareVolume(const char *label, const char *method) {
1012 Volume *v = lookupVolume(label);
1013
1014 if (!v) {
1015 errno = ENOENT;
1016 return -1;
1017 }
1018
1019 /*
1020 * Eventually, we'll want to support additional share back-ends,
1021 * some of which may work while the media is mounted. For now,
1022 * we just support UMS
1023 */
1024 if (strcmp(method, "ums")) {
1025 errno = ENOSYS;
1026 return -1;
1027 }
1028
1029 if (v->getState() == Volume::State_NoMedia) {
1030 errno = ENODEV;
1031 return -1;
1032 }
1033
San Mehat49e2bce2009-10-12 16:29:01 -07001034 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -08001035 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -07001036 errno = EBUSY;
1037 return -1;
1038 }
1039
Mike Lockwood2dfe2972010-09-17 18:50:51 -04001040 dev_t d = v->getShareDevice();
San Mehata2677e42009-12-13 10:40:18 -08001041 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
1042 // This volume does not support raw disk access
1043 errno = EINVAL;
1044 return -1;
1045 }
1046
1047 int fd;
1048 char nodepath[255];
1049 snprintf(nodepath,
1050 sizeof(nodepath), "/dev/block/vold/%d:%d",
1051 MAJOR(d), MINOR(d));
1052
San Mehat0cde53c2009-12-22 08:32:33 -08001053 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file",
1054 O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001055 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001056 return -1;
1057 }
1058
1059 if (write(fd, nodepath, strlen(nodepath)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001060 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001061 close(fd);
1062 return -1;
1063 }
1064
1065 close(fd);
1066 v->handleVolumeShared();
1067 return 0;
1068}
1069
1070int VolumeManager::unshareVolume(const char *label, const char *method) {
1071 Volume *v = lookupVolume(label);
1072
1073 if (!v) {
1074 errno = ENOENT;
1075 return -1;
1076 }
1077
1078 if (strcmp(method, "ums")) {
1079 errno = ENOSYS;
1080 return -1;
1081 }
1082
1083 if (v->getState() != Volume::State_Shared) {
1084 errno = EINVAL;
1085 return -1;
1086 }
1087
San Mehata2677e42009-12-13 10:40:18 -08001088 int fd;
San Mehat0cde53c2009-12-22 08:32:33 -08001089 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file", O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001090 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001091 return -1;
1092 }
1093
1094 char ch = 0;
1095 if (write(fd, &ch, 1) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001096 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001097 close(fd);
1098 return -1;
1099 }
1100
1101 close(fd);
1102 v->handleVolumeUnshared();
1103 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -07001104}
1105
San Mehat4ba89482010-02-18 09:00:18 -08001106int VolumeManager::unmountVolume(const char *label, bool force) {
San Mehat49e2bce2009-10-12 16:29:01 -07001107 Volume *v = lookupVolume(label);
1108
1109 if (!v) {
1110 errno = ENOENT;
1111 return -1;
1112 }
1113
San Mehata2677e42009-12-13 10:40:18 -08001114 if (v->getState() == Volume::State_NoMedia) {
1115 errno = ENODEV;
1116 return -1;
1117 }
1118
San Mehat49e2bce2009-10-12 16:29:01 -07001119 if (v->getState() != Volume::State_Mounted) {
San Mehat97ac40e2010-03-24 10:24:19 -07001120 SLOGW("Attempt to unmount volume which isn't mounted (%d)\n",
San Mehata2677e42009-12-13 10:40:18 -08001121 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -07001122 errno = EBUSY;
1123 return -1;
1124 }
1125
San Mehat1a06eda2010-04-15 12:58:50 -07001126 cleanupAsec(v, force);
San Mehat88705162010-01-15 09:26:28 -08001127
San Mehat4ba89482010-02-18 09:00:18 -08001128 return v->unmountVol(force);
San Mehat49e2bce2009-10-12 16:29:01 -07001129}
1130
San Mehata2677e42009-12-13 10:40:18 -08001131/*
1132 * Looks up a volume by it's label or mount-point
1133 */
San Mehat49e2bce2009-10-12 16:29:01 -07001134Volume *VolumeManager::lookupVolume(const char *label) {
1135 VolumeCollection::iterator i;
1136
1137 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -08001138 if (label[0] == '/') {
1139 if (!strcmp(label, (*i)->getMountpoint()))
1140 return (*i);
1141 } else {
1142 if (!strcmp(label, (*i)->getLabel()))
1143 return (*i);
1144 }
San Mehat49e2bce2009-10-12 16:29:01 -07001145 }
1146 return NULL;
1147}
San Mehata19b2502010-01-06 10:33:53 -08001148
1149bool VolumeManager::isMountpointMounted(const char *mp)
1150{
1151 char device[256];
1152 char mount_path[256];
1153 char rest[256];
1154 FILE *fp;
1155 char line[1024];
1156
1157 if (!(fp = fopen("/proc/mounts", "r"))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001158 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001159 return false;
1160 }
1161
1162 while(fgets(line, sizeof(line), fp)) {
1163 line[strlen(line)-1] = '\0';
1164 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1165 if (!strcmp(mount_path, mp)) {
1166 fclose(fp);
1167 return true;
1168 }
San Mehata19b2502010-01-06 10:33:53 -08001169 }
1170
1171 fclose(fp);
1172 return false;
1173}
1174
San Mehat1a06eda2010-04-15 12:58:50 -07001175int VolumeManager::cleanupAsec(Volume *v, bool force) {
1176 while(mActiveContainers->size()) {
1177 AsecIdCollection::iterator it = mActiveContainers->begin();
Kenny Rootcbacf782010-09-24 15:11:48 -07001178 ContainerData* cd = *it;
1179 SLOGI("Unmounting ASEC %s (dependant on %s)", cd->id, v->getMountpoint());
1180 if (cd->type == ASEC) {
1181 if (unmountAsec(cd->id, force)) {
1182 SLOGE("Failed to unmount ASEC %s (%s)", cd->id, strerror(errno));
1183 return -1;
1184 }
1185 } else if (cd->type == OBB) {
1186 if (unmountObb(cd->id, force)) {
1187 SLOGE("Failed to unmount OBB %s (%s)", cd->id, strerror(errno));
1188 return -1;
1189 }
1190 } else {
1191 SLOGE("Unknown container type %d!", cd->type);
San Mehat1a06eda2010-04-15 12:58:50 -07001192 return -1;
1193 }
1194 }
1195 return 0;
1196}
1197