blob: c1406a9950121d1792d5448b2dcdc6004df96d8d [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
Mike Lockwood97f2fc12011-06-07 10:51:38 -070046#define MASS_STORAGE_FILE_PATH "/sys/class/android_usb/android0/f_mass_storage/lun/file"
47
San Mehatf1b736b2009-10-10 17:22:08 -070048VolumeManager *VolumeManager::sInstance = NULL;
49
50VolumeManager *VolumeManager::Instance() {
51 if (!sInstance)
52 sInstance = new VolumeManager();
53 return sInstance;
54}
55
56VolumeManager::VolumeManager() {
San Mehatd9a4e352010-03-12 13:32:47 -080057 mDebug = false;
San Mehatf1b736b2009-10-10 17:22:08 -070058 mVolumes = new VolumeCollection();
San Mehat88705162010-01-15 09:26:28 -080059 mActiveContainers = new AsecIdCollection();
San Mehatf1b736b2009-10-10 17:22:08 -070060 mBroadcaster = NULL;
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;
San Mehatf1b736b2009-10-10 17:22:08 -070065}
66
67VolumeManager::~VolumeManager() {
San Mehat88705162010-01-15 09:26:28 -080068 delete mVolumes;
69 delete mActiveContainers;
San Mehatf1b736b2009-10-10 17:22:08 -070070}
71
Kenny Root7b18a7b2010-03-15 13:13:41 -070072char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -070073 static const char* digits = "0123456789abcdef";
74
Kenny Root7b18a7b2010-03-15 13:13:41 -070075 unsigned char sig[MD5_DIGEST_LENGTH];
76
Kenny Rootacc9e7d2010-06-18 19:06:50 -070077 if (buffer == NULL) {
78 SLOGE("Destination buffer is NULL");
79 errno = ESPIPE;
80 return NULL;
81 } else if (id == NULL) {
82 SLOGE("Source buffer is NULL");
83 errno = ESPIPE;
84 return NULL;
85 } else if (len < MD5_ASCII_LENGTH_PLUS_NULL) {
86 SLOGE("Target hash buffer size < %d bytes (%d)",
87 MD5_ASCII_LENGTH_PLUS_NULL, len);
San Mehatd9a4e352010-03-12 13:32:47 -080088 errno = ESPIPE;
89 return NULL;
90 }
Kenny Root7b18a7b2010-03-15 13:13:41 -070091
92 MD5(reinterpret_cast<const unsigned char*>(id), strlen(id), sig);
San Mehatd9a4e352010-03-12 13:32:47 -080093
Kenny Rootacc9e7d2010-06-18 19:06:50 -070094 char *p = buffer;
Kenny Root7b18a7b2010-03-15 13:13:41 -070095 for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -070096 *p++ = digits[sig[i] >> 4];
97 *p++ = digits[sig[i] & 0x0F];
San Mehatd9a4e352010-03-12 13:32:47 -080098 }
Kenny Rootacc9e7d2010-06-18 19:06:50 -070099 *p = '\0';
San Mehatd9a4e352010-03-12 13:32:47 -0800100
101 return buffer;
102}
103
104void VolumeManager::setDebug(bool enable) {
105 mDebug = enable;
106 VolumeCollection::iterator it;
107 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
108 (*it)->setDebug(enable);
109 }
110}
111
San Mehatf1b736b2009-10-10 17:22:08 -0700112int VolumeManager::start() {
113 return 0;
114}
115
116int VolumeManager::stop() {
117 return 0;
118}
119
120int VolumeManager::addVolume(Volume *v) {
121 mVolumes->push_back(v);
122 return 0;
123}
124
San Mehatfd7f5872009-10-12 11:32:47 -0700125void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
126 const char *devpath = evt->findParam("DEVPATH");
San Mehatf1b736b2009-10-10 17:22:08 -0700127
San Mehatfd7f5872009-10-12 11:32:47 -0700128 /* Lookup a volume to handle this device */
San Mehatf1b736b2009-10-10 17:22:08 -0700129 VolumeCollection::iterator it;
130 bool hit = false;
131 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
San Mehatfd7f5872009-10-12 11:32:47 -0700132 if (!(*it)->handleBlockEvent(evt)) {
San Mehata2677e42009-12-13 10:40:18 -0800133#ifdef NETLINK_DEBUG
San Mehat97ac40e2010-03-24 10:24:19 -0700134 SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
San Mehata2677e42009-12-13 10:40:18 -0800135#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700136 hit = true;
San Mehatf1b736b2009-10-10 17:22:08 -0700137 break;
138 }
139 }
140
141 if (!hit) {
San Mehata2677e42009-12-13 10:40:18 -0800142#ifdef NETLINK_DEBUG
San Mehat97ac40e2010-03-24 10:24:19 -0700143 SLOGW("No volumes handled block event for '%s'", devpath);
San Mehata2677e42009-12-13 10:40:18 -0800144#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700145 }
146}
147
San Mehatf1b736b2009-10-10 17:22:08 -0700148int VolumeManager::listVolumes(SocketClient *cli) {
149 VolumeCollection::iterator i;
150
151 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
152 char *buffer;
153 asprintf(&buffer, "%s %s %d",
154 (*i)->getLabel(), (*i)->getMountpoint(),
155 (*i)->getState());
San Mehata2677e42009-12-13 10:40:18 -0800156 cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
San Mehatf1b736b2009-10-10 17:22:08 -0700157 free(buffer);
158 }
San Mehata2677e42009-12-13 10:40:18 -0800159 cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
San Mehatf1b736b2009-10-10 17:22:08 -0700160 return 0;
161}
San Mehat49e2bce2009-10-12 16:29:01 -0700162
San Mehata2677e42009-12-13 10:40:18 -0800163int VolumeManager::formatVolume(const char *label) {
164 Volume *v = lookupVolume(label);
165
166 if (!v) {
167 errno = ENOENT;
168 return -1;
169 }
170
171 return v->formatVol();
172}
173
Kenny Root508c0e12010-07-12 09:59:49 -0700174int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) {
175 char idHash[33];
176 if (!asecHash(sourceFile, idHash, sizeof(idHash))) {
177 SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno));
178 return -1;
179 }
180
181 memset(mountPath, 0, mountPathLen);
182 snprintf(mountPath, mountPathLen, "%s/%s", Volume::LOOPDIR, idHash);
183
184 if (access(mountPath, F_OK)) {
185 errno = ENOENT;
186 return -1;
187 }
188
189 return 0;
190}
191
San Mehata19b2502010-01-06 10:33:53 -0800192int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
San Mehat88ac2c02010-03-23 11:15:58 -0700193 char asecFileName[255];
194 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
195
196 memset(buffer, 0, maxlen);
197 if (access(asecFileName, F_OK)) {
198 errno = ENOENT;
199 return -1;
200 }
San Mehata19b2502010-01-06 10:33:53 -0800201
San Mehat3bb60202010-02-19 18:14:36 -0800202 snprintf(buffer, maxlen, "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800203 return 0;
204}
205
Dianne Hackborn736910c2011-06-27 13:37:07 -0700206int VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxlen) {
207 char asecFileName[255];
208 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
209
210 memset(buffer, 0, maxlen);
211 if (access(asecFileName, F_OK)) {
212 errno = ENOENT;
213 return -1;
214 }
215
216 snprintf(buffer, maxlen, "%s", asecFileName);
217 return 0;
218}
219
San Mehat8b8f71b2010-01-11 09:17:25 -0800220int VolumeManager::createAsec(const char *id, unsigned int numSectors,
San Mehata19b2502010-01-06 10:33:53 -0800221 const char *fstype, const char *key, int ownerUid) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800222 struct asec_superblock sb;
223 memset(&sb, 0, sizeof(sb));
224
225 sb.magic = ASEC_SB_MAGIC;
226 sb.ver = ASEC_SB_VER;
San Mehata19b2502010-01-06 10:33:53 -0800227
San Mehatd31e3802010-02-18 08:37:45 -0800228 if (numSectors < ((1024*1024)/512)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700229 SLOGE("Invalid container size specified (%d sectors)", numSectors);
San Mehatd31e3802010-02-18 08:37:45 -0800230 errno = EINVAL;
231 return -1;
232 }
233
San Mehata19b2502010-01-06 10:33:53 -0800234 if (lookupVolume(id)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700235 SLOGE("ASEC id '%s' currently exists", id);
San Mehata19b2502010-01-06 10:33:53 -0800236 errno = EADDRINUSE;
237 return -1;
238 }
239
240 char asecFileName[255];
San Mehat3bb60202010-02-19 18:14:36 -0800241 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800242
243 if (!access(asecFileName, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700244 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
San Mehata19b2502010-01-06 10:33:53 -0800245 asecFileName, strerror(errno));
246 errno = EADDRINUSE;
247 return -1;
248 }
249
San Mehatfcf24fe2010-03-03 12:37:32 -0800250 /*
251 * Add some headroom
252 */
253 unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
254 unsigned numImgSectors = numSectors + fatSize + 2;
255
256 if (numImgSectors % 63) {
257 numImgSectors += (63 - (numImgSectors % 63));
258 }
259
260 // Add +1 for our superblock which is at the end
261 if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700262 SLOGE("ASEC image file creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800263 return -1;
264 }
265
San Mehatd9a4e352010-03-12 13:32:47 -0800266 char idHash[33];
267 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700268 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800269 unlink(asecFileName);
270 return -1;
271 }
272
San Mehata19b2502010-01-06 10:33:53 -0800273 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800274 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700275 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800276 unlink(asecFileName);
277 return -1;
278 }
279
San Mehatb78a32c2010-01-10 13:02:12 -0800280 char dmDevice[255];
281 bool cleanupDm = false;
San Mehata19b2502010-01-06 10:33:53 -0800282
San Mehatb78a32c2010-01-10 13:02:12 -0800283 if (strcmp(key, "none")) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800284 // XXX: This is all we support for now
285 sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
San Mehatd9a4e352010-03-12 13:32:47 -0800286 if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
San Mehatb78a32c2010-01-10 13:02:12 -0800287 sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700288 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800289 Loop::destroyByDevice(loopDevice);
290 unlink(asecFileName);
291 return -1;
292 }
293 cleanupDm = true;
294 } else {
San Mehatfcf24fe2010-03-03 12:37:32 -0800295 sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
San Mehatb78a32c2010-01-10 13:02:12 -0800296 strcpy(dmDevice, loopDevice);
297 }
298
San Mehatfcf24fe2010-03-03 12:37:32 -0800299 /*
300 * Drop down the superblock at the end of the file
301 */
302
303 int sbfd = open(loopDevice, O_RDWR);
304 if (sbfd < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700305 SLOGE("Failed to open new DM device for superblock write (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800306 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800307 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800308 }
309 Loop::destroyByDevice(loopDevice);
310 unlink(asecFileName);
311 return -1;
312 }
313
314 if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
315 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700316 SLOGE("Failed to lseek for superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800317 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800318 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800319 }
320 Loop::destroyByDevice(loopDevice);
321 unlink(asecFileName);
322 return -1;
323 }
324
325 if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) {
326 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700327 SLOGE("Failed to write superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800328 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800329 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800330 }
331 Loop::destroyByDevice(loopDevice);
332 unlink(asecFileName);
333 return -1;
334 }
335 close(sbfd);
336
San Mehata1091cb2010-02-28 20:17:20 -0800337 if (strcmp(fstype, "none")) {
338 if (strcmp(fstype, "fat")) {
San Mehat97ac40e2010-03-24 10:24:19 -0700339 SLOGW("Unknown fstype '%s' specified for container", fstype);
San Mehatb78a32c2010-01-10 13:02:12 -0800340 }
San Mehata19b2502010-01-06 10:33:53 -0800341
San Mehatfcf24fe2010-03-03 12:37:32 -0800342 if (Fat::format(dmDevice, numImgSectors)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700343 SLOGE("ASEC FAT format failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800344 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800345 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800346 }
San Mehateb13a902010-01-07 12:12:50 -0800347 Loop::destroyByDevice(loopDevice);
348 unlink(asecFileName);
349 return -1;
350 }
San Mehata1091cb2010-02-28 20:17:20 -0800351 char mountPoint[255];
San Mehata19b2502010-01-06 10:33:53 -0800352
San Mehata1091cb2010-02-28 20:17:20 -0800353 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
354 if (mkdir(mountPoint, 0777)) {
355 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -0700356 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800357 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800358 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800359 }
360 Loop::destroyByDevice(loopDevice);
361 unlink(asecFileName);
362 return -1;
363 }
San Mehatb78a32c2010-01-10 13:02:12 -0800364 }
San Mehata1091cb2010-02-28 20:17:20 -0800365
Kenny Roota3e06082010-08-27 08:31:35 -0700366 if (Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid,
San Mehata1091cb2010-02-28 20:17:20 -0800367 0, 0000, false)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700368 SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800369 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800370 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800371 }
372 Loop::destroyByDevice(loopDevice);
373 unlink(asecFileName);
374 return -1;
375 }
376 } else {
San Mehat97ac40e2010-03-24 10:24:19 -0700377 SLOGI("Created raw secure container %s (no filesystem)", id);
San Mehata19b2502010-01-06 10:33:53 -0800378 }
San Mehat88705162010-01-15 09:26:28 -0800379
Kenny Rootcbacf782010-09-24 15:11:48 -0700380 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehata19b2502010-01-06 10:33:53 -0800381 return 0;
382}
383
384int VolumeManager::finalizeAsec(const char *id) {
385 char asecFileName[255];
386 char loopDevice[255];
387 char mountPoint[255];
388
San Mehat3bb60202010-02-19 18:14:36 -0800389 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800390
San Mehatd9a4e352010-03-12 13:32:47 -0800391 char idHash[33];
392 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700393 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800394 return -1;
395 }
396
397 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700398 SLOGE("Unable to finalize %s (%s)", id, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800399 return -1;
400 }
401
San Mehat3bb60202010-02-19 18:14:36 -0800402 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatfff0b472010-01-06 19:19:46 -0800403 // XXX:
Kenny Roota3e06082010-08-27 08:31:35 -0700404 if (Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700405 SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800406 return -1;
407 }
408
San Mehatd9a4e352010-03-12 13:32:47 -0800409 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700410 SLOGD("ASEC %s finalized", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800411 }
San Mehata19b2502010-01-06 10:33:53 -0800412 return 0;
413}
414
San Mehat048b0802010-01-23 08:17:06 -0800415int VolumeManager::renameAsec(const char *id1, const char *id2) {
416 char *asecFilename1;
417 char *asecFilename2;
418 char mountPoint[255];
419
San Mehat3bb60202010-02-19 18:14:36 -0800420 asprintf(&asecFilename1, "%s/%s.asec", Volume::SEC_ASECDIR, id1);
421 asprintf(&asecFilename2, "%s/%s.asec", Volume::SEC_ASECDIR, id2);
San Mehat048b0802010-01-23 08:17:06 -0800422
San Mehat3bb60202010-02-19 18:14:36 -0800423 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
San Mehat048b0802010-01-23 08:17:06 -0800424 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700425 SLOGW("Rename attempt when src mounted");
San Mehat048b0802010-01-23 08:17:06 -0800426 errno = EBUSY;
427 goto out_err;
428 }
429
San Mehat96956ed2010-02-24 08:42:51 -0800430 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2);
431 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700432 SLOGW("Rename attempt when dst mounted");
San Mehat96956ed2010-02-24 08:42:51 -0800433 errno = EBUSY;
434 goto out_err;
435 }
436
San Mehat048b0802010-01-23 08:17:06 -0800437 if (!access(asecFilename2, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700438 SLOGE("Rename attempt when dst exists");
San Mehat048b0802010-01-23 08:17:06 -0800439 errno = EADDRINUSE;
440 goto out_err;
441 }
442
443 if (rename(asecFilename1, asecFilename2)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700444 SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
San Mehat048b0802010-01-23 08:17:06 -0800445 goto out_err;
446 }
447
448 free(asecFilename1);
449 free(asecFilename2);
450 return 0;
451
452out_err:
453 free(asecFilename1);
454 free(asecFilename2);
455 return -1;
456}
457
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700458#define UNMOUNT_RETRIES 5
459#define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
San Mehat4ba89482010-02-18 09:00:18 -0800460int VolumeManager::unmountAsec(const char *id, bool force) {
San Mehata19b2502010-01-06 10:33:53 -0800461 char asecFileName[255];
462 char mountPoint[255];
463
San Mehat3bb60202010-02-19 18:14:36 -0800464 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
465 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800466
San Mehatd9a4e352010-03-12 13:32:47 -0800467 char idHash[33];
468 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700469 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800470 return -1;
471 }
472
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700473 return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
474}
475
Kenny Root508c0e12010-07-12 09:59:49 -0700476int VolumeManager::unmountObb(const char *fileName, bool force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700477 char mountPoint[255];
478
479 char idHash[33];
480 if (!asecHash(fileName, idHash, sizeof(idHash))) {
481 SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
482 return -1;
483 }
484
485 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
486
487 return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
488}
489
490int VolumeManager::unmountLoopImage(const char *id, const char *idHash,
491 const char *fileName, const char *mountPoint, bool force) {
San Mehat0586d542010-01-12 15:38:59 -0800492 if (!isMountpointMounted(mountPoint)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700493 SLOGE("Unmount request for %s when not mounted", id);
Kenny Root918e5f92010-09-30 18:00:52 -0700494 errno = ENOENT;
San Mehatb78a32c2010-01-10 13:02:12 -0800495 return -1;
496 }
San Mehat23969932010-01-09 07:08:06 -0800497
San Mehatb78a32c2010-01-10 13:02:12 -0800498 int i, rc;
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700499 for (i = 1; i <= UNMOUNT_RETRIES; i++) {
San Mehatb78a32c2010-01-10 13:02:12 -0800500 rc = umount(mountPoint);
501 if (!rc) {
502 break;
San Mehata19b2502010-01-06 10:33:53 -0800503 }
San Mehatb78a32c2010-01-10 13:02:12 -0800504 if (rc && (errno == EINVAL || errno == ENOENT)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700505 SLOGI("Container %s unmounted OK", id);
San Mehatb78a32c2010-01-10 13:02:12 -0800506 rc = 0;
507 break;
San Mehata19b2502010-01-06 10:33:53 -0800508 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700509 SLOGW("%s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -0800510 id, i, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800511
San Mehat4ba89482010-02-18 09:00:18 -0800512 int action = 0; // default is to just complain
513
514 if (force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700515 if (i > (UNMOUNT_RETRIES - 2))
San Mehat4ba89482010-02-18 09:00:18 -0800516 action = 2; // SIGKILL
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700517 else if (i > (UNMOUNT_RETRIES - 3))
San Mehat4ba89482010-02-18 09:00:18 -0800518 action = 1; // SIGHUP
519 }
San Mehat8c940ef2010-02-13 14:19:53 -0800520
San Mehat586536c2010-02-16 17:12:00 -0800521 Process::killProcessesWithOpenFiles(mountPoint, action);
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700522 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehatb78a32c2010-01-10 13:02:12 -0800523 }
524
525 if (rc) {
San Mehat4ba89482010-02-18 09:00:18 -0800526 errno = EBUSY;
San Mehat97ac40e2010-03-24 10:24:19 -0700527 SLOGE("Failed to unmount container %s (%s)", id, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800528 return -1;
529 }
530
San Mehat12f4b892010-02-24 11:43:22 -0800531 int retries = 10;
532
533 while(retries--) {
534 if (!rmdir(mountPoint)) {
535 break;
536 }
537
San Mehat97ac40e2010-03-24 10:24:19 -0700538 SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700539 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehat12f4b892010-02-24 11:43:22 -0800540 }
541
542 if (!retries) {
San Mehat97ac40e2010-03-24 10:24:19 -0700543 SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
San Mehatf5c61982010-02-03 11:04:46 -0800544 }
San Mehat88705162010-01-15 09:26:28 -0800545
San Mehatd9a4e352010-03-12 13:32:47 -0800546 if (Devmapper::destroy(idHash) && errno != ENXIO) {
San Mehat97ac40e2010-03-24 10:24:19 -0700547 SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800548 }
549
550 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800551 if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800552 Loop::destroyByDevice(loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800553 } else {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700554 SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800555 }
San Mehat88705162010-01-15 09:26:28 -0800556
557 AsecIdCollection::iterator it;
558 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
Kenny Rootcbacf782010-09-24 15:11:48 -0700559 ContainerData* cd = *it;
560 if (!strcmp(cd->id, id)) {
San Mehat88705162010-01-15 09:26:28 -0800561 free(*it);
562 mActiveContainers->erase(it);
563 break;
564 }
565 }
566 if (it == mActiveContainers->end()) {
San Mehat97ac40e2010-03-24 10:24:19 -0700567 SLOGW("mActiveContainers is inconsistent!");
San Mehat88705162010-01-15 09:26:28 -0800568 }
San Mehatb78a32c2010-01-10 13:02:12 -0800569 return 0;
570}
571
San Mehat4ba89482010-02-18 09:00:18 -0800572int VolumeManager::destroyAsec(const char *id, bool force) {
San Mehatb78a32c2010-01-10 13:02:12 -0800573 char asecFileName[255];
574 char mountPoint[255];
575
San Mehat3bb60202010-02-19 18:14:36 -0800576 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehat55013f72010-02-24 12:12:34 -0800577 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatb78a32c2010-01-10 13:02:12 -0800578
San Mehat0586d542010-01-12 15:38:59 -0800579 if (isMountpointMounted(mountPoint)) {
San Mehatd9a4e352010-03-12 13:32:47 -0800580 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700581 SLOGD("Unmounting container before destroy");
San Mehatd9a4e352010-03-12 13:32:47 -0800582 }
San Mehat4ba89482010-02-18 09:00:18 -0800583 if (unmountAsec(id, force)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700584 SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800585 return -1;
586 }
587 }
San Mehata19b2502010-01-06 10:33:53 -0800588
San Mehat0586d542010-01-12 15:38:59 -0800589 if (unlink(asecFileName)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700590 SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800591 return -1;
592 }
San Mehata19b2502010-01-06 10:33:53 -0800593
San Mehatd9a4e352010-03-12 13:32:47 -0800594 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700595 SLOGD("ASEC %s destroyed", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800596 }
San Mehata19b2502010-01-06 10:33:53 -0800597 return 0;
598}
599
600int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
601 char asecFileName[255];
602 char mountPoint[255];
603
San Mehat3bb60202010-02-19 18:14:36 -0800604 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
605 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800606
607 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700608 SLOGE("ASEC %s already mounted", id);
San Mehata19b2502010-01-06 10:33:53 -0800609 errno = EBUSY;
610 return -1;
611 }
612
San Mehatd9a4e352010-03-12 13:32:47 -0800613 char idHash[33];
614 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700615 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800616 return -1;
617 }
Kenny Root7b18a7b2010-03-15 13:13:41 -0700618
San Mehata19b2502010-01-06 10:33:53 -0800619 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800620 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
621 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700622 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800623 return -1;
624 }
San Mehatd9a4e352010-03-12 13:32:47 -0800625 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700626 SLOGD("New loop device created at %s", loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800627 }
San Mehatb78a32c2010-01-10 13:02:12 -0800628 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800629 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700630 SLOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800631 }
San Mehatb78a32c2010-01-10 13:02:12 -0800632 }
633
634 char dmDevice[255];
635 bool cleanupDm = false;
San Mehatfcf24fe2010-03-03 12:37:32 -0800636 int fd;
637 unsigned int nr_sec = 0;
638
639 if ((fd = open(loopDevice, O_RDWR)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700640 SLOGE("Failed to open loopdevice (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800641 Loop::destroyByDevice(loopDevice);
642 return -1;
643 }
644
645 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700646 SLOGE("Failed to get loop size (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800647 Loop::destroyByDevice(loopDevice);
648 close(fd);
649 return -1;
650 }
651
652 /*
653 * Validate superblock
654 */
655 struct asec_superblock sb;
656 memset(&sb, 0, sizeof(sb));
657 if (lseek(fd, ((nr_sec-1) * 512), SEEK_SET) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700658 SLOGE("lseek failed (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800659 close(fd);
660 Loop::destroyByDevice(loopDevice);
661 return -1;
662 }
663 if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700664 SLOGE("superblock read failed (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800665 close(fd);
666 Loop::destroyByDevice(loopDevice);
667 return -1;
668 }
669
670 close(fd);
671
San Mehatd9a4e352010-03-12 13:32:47 -0800672 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700673 SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatd9a4e352010-03-12 13:32:47 -0800674 }
San Mehatfcf24fe2010-03-03 12:37:32 -0800675 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
San Mehat97ac40e2010-03-24 10:24:19 -0700676 SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatfcf24fe2010-03-03 12:37:32 -0800677 Loop::destroyByDevice(loopDevice);
678 errno = EMEDIUMTYPE;
679 return -1;
680 }
681 nr_sec--; // We don't want the devmapping to extend onto our superblock
682
San Mehatb78a32c2010-01-10 13:02:12 -0800683 if (strcmp(key, "none")) {
San Mehatd9a4e352010-03-12 13:32:47 -0800684 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
685 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
San Mehatb78a32c2010-01-10 13:02:12 -0800686 dmDevice, sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700687 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800688 Loop::destroyByDevice(loopDevice);
689 return -1;
690 }
San Mehatd9a4e352010-03-12 13:32:47 -0800691 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700692 SLOGD("New devmapper instance created at %s", dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800693 }
San Mehatb78a32c2010-01-10 13:02:12 -0800694 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800695 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700696 SLOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800697 }
San Mehatb78a32c2010-01-10 13:02:12 -0800698 }
699 cleanupDm = true;
700 } else {
701 strcpy(dmDevice, loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800702 }
703
704 if (mkdir(mountPoint, 0777)) {
San Mehatb78a32c2010-01-10 13:02:12 -0800705 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -0700706 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800707 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800708 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800709 }
710 Loop::destroyByDevice(loopDevice);
711 return -1;
712 }
San Mehata19b2502010-01-06 10:33:53 -0800713 }
714
Kenny Roota3e06082010-08-27 08:31:35 -0700715 if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0,
San Mehatcff5ec32010-01-08 12:31:44 -0800716 0222, false)) {
717// 0227, false)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700718 SLOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800719 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800720 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800721 }
722 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800723 return -1;
724 }
725
Kenny Rootcbacf782010-09-24 15:11:48 -0700726 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehatd9a4e352010-03-12 13:32:47 -0800727 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700728 SLOGD("ASEC %s mounted", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800729 }
San Mehata19b2502010-01-06 10:33:53 -0800730 return 0;
731}
732
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700733/**
734 * Mounts an image file <code>img</code>.
735 */
Kenny Root508c0e12010-07-12 09:59:49 -0700736int VolumeManager::mountObb(const char *img, const char *key, int ownerUid) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700737 char mountPoint[255];
738
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700739 char idHash[33];
740 if (!asecHash(img, idHash, sizeof(idHash))) {
741 SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
742 return -1;
743 }
744
745 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
746
747 if (isMountpointMounted(mountPoint)) {
748 SLOGE("Image %s already mounted", img);
749 errno = EBUSY;
750 return -1;
751 }
752
753 char loopDevice[255];
754 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
755 if (Loop::create(idHash, img, loopDevice, sizeof(loopDevice))) {
756 SLOGE("Image loop device creation failed (%s)", strerror(errno));
757 return -1;
758 }
759 if (mDebug) {
760 SLOGD("New loop device created at %s", loopDevice);
761 }
762 } else {
763 if (mDebug) {
764 SLOGD("Found active loopback for %s at %s", img, loopDevice);
765 }
766 }
767
768 char dmDevice[255];
769 bool cleanupDm = false;
770 int fd;
771 unsigned int nr_sec = 0;
772
773 if ((fd = open(loopDevice, O_RDWR)) < 0) {
774 SLOGE("Failed to open loopdevice (%s)", strerror(errno));
775 Loop::destroyByDevice(loopDevice);
776 return -1;
777 }
778
779 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
780 SLOGE("Failed to get loop size (%s)", strerror(errno));
781 Loop::destroyByDevice(loopDevice);
782 close(fd);
783 return -1;
784 }
785
786 close(fd);
787
788 if (strcmp(key, "none")) {
789 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
790 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
791 dmDevice, sizeof(dmDevice))) {
792 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
793 Loop::destroyByDevice(loopDevice);
794 return -1;
795 }
796 if (mDebug) {
797 SLOGD("New devmapper instance created at %s", dmDevice);
798 }
799 } else {
800 if (mDebug) {
801 SLOGD("Found active devmapper for %s at %s", img, dmDevice);
802 }
803 }
804 cleanupDm = true;
805 } else {
806 strcpy(dmDevice, loopDevice);
807 }
808
809 if (mkdir(mountPoint, 0755)) {
810 if (errno != EEXIST) {
811 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
812 if (cleanupDm) {
813 Devmapper::destroy(idHash);
814 }
815 Loop::destroyByDevice(loopDevice);
816 return -1;
817 }
818 }
819
Kenny Roota3e06082010-08-27 08:31:35 -0700820 if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0,
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700821 0227, false)) {
822 SLOGE("Image mount failed (%s)", strerror(errno));
823 if (cleanupDm) {
824 Devmapper::destroy(idHash);
825 }
826 Loop::destroyByDevice(loopDevice);
827 return -1;
828 }
829
Kenny Rootcbacf782010-09-24 15:11:48 -0700830 mActiveContainers->push_back(new ContainerData(strdup(img), OBB));
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700831 if (mDebug) {
832 SLOGD("Image %s mounted", img);
833 }
834 return 0;
835}
836
San Mehat49e2bce2009-10-12 16:29:01 -0700837int VolumeManager::mountVolume(const char *label) {
838 Volume *v = lookupVolume(label);
839
840 if (!v) {
841 errno = ENOENT;
842 return -1;
843 }
844
San Mehata2677e42009-12-13 10:40:18 -0800845 return v->mountVol();
846}
847
Kenny Root508c0e12010-07-12 09:59:49 -0700848int VolumeManager::listMountedObbs(SocketClient* cli) {
849 char device[256];
850 char mount_path[256];
851 char rest[256];
852 FILE *fp;
853 char line[1024];
854
855 if (!(fp = fopen("/proc/mounts", "r"))) {
856 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
857 return -1;
858 }
859
860 // Create a string to compare against that has a trailing slash
861 int loopDirLen = sizeof(Volume::LOOPDIR);
862 char loopDir[loopDirLen + 2];
863 strcpy(loopDir, Volume::LOOPDIR);
864 loopDir[loopDirLen++] = '/';
865 loopDir[loopDirLen] = '\0';
866
867 while(fgets(line, sizeof(line), fp)) {
868 line[strlen(line)-1] = '\0';
869
870 /*
871 * Should look like:
872 * /dev/block/loop0 /mnt/obb/fc99df1323fd36424f864dcb76b76d65 ...
873 */
874 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
875
876 if (!strncmp(mount_path, loopDir, loopDirLen)) {
877 int fd = open(device, O_RDONLY);
878 if (fd >= 0) {
879 struct loop_info64 li;
880 if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
881 cli->sendMsg(ResponseCode::AsecListResult,
882 (const char*) li.lo_file_name, false);
883 }
884 close(fd);
885 }
886 }
887 }
888
889 fclose(fp);
890 return 0;
891}
892
San Mehateba65e92010-01-29 05:15:16 -0800893int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
894 Volume *v = lookupVolume(label);
895
896 if (!v) {
897 errno = ENOENT;
898 return -1;
899 }
900
901 if (strcmp(method, "ums")) {
902 errno = ENOSYS;
903 return -1;
904 }
905
906 if (v->getState() != Volume::State_Shared) {
San Mehateba65e92010-01-29 05:15:16 -0800907 *enabled = false;
San Mehatb9aed742010-02-04 15:07:01 -0800908 } else {
909 *enabled = true;
San Mehateba65e92010-01-29 05:15:16 -0800910 }
911 return 0;
912}
913
San Mehata2677e42009-12-13 10:40:18 -0800914int VolumeManager::shareVolume(const char *label, const char *method) {
915 Volume *v = lookupVolume(label);
916
917 if (!v) {
918 errno = ENOENT;
919 return -1;
920 }
921
922 /*
923 * Eventually, we'll want to support additional share back-ends,
924 * some of which may work while the media is mounted. For now,
925 * we just support UMS
926 */
927 if (strcmp(method, "ums")) {
928 errno = ENOSYS;
929 return -1;
930 }
931
932 if (v->getState() == Volume::State_NoMedia) {
933 errno = ENODEV;
934 return -1;
935 }
936
San Mehat49e2bce2009-10-12 16:29:01 -0700937 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -0800938 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -0700939 errno = EBUSY;
940 return -1;
941 }
942
Mike Lockwood2dfe2972010-09-17 18:50:51 -0400943 dev_t d = v->getShareDevice();
San Mehata2677e42009-12-13 10:40:18 -0800944 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
945 // This volume does not support raw disk access
946 errno = EINVAL;
947 return -1;
948 }
949
950 int fd;
951 char nodepath[255];
952 snprintf(nodepath,
953 sizeof(nodepath), "/dev/block/vold/%d:%d",
954 MAJOR(d), MINOR(d));
955
Mike Lockwood97f2fc12011-06-07 10:51:38 -0700956 if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700957 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -0800958 return -1;
959 }
960
961 if (write(fd, nodepath, strlen(nodepath)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700962 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -0800963 close(fd);
964 return -1;
965 }
966
967 close(fd);
968 v->handleVolumeShared();
Mike Lockwooda28056b2010-10-28 15:21:24 -0400969 if (mUmsSharingCount++ == 0) {
970 FILE* fp;
971 mSavedDirtyRatio = -1; // in case we fail
972 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
973 char line[16];
974 if (fgets(line, sizeof(line), fp) && sscanf(line, "%d", &mSavedDirtyRatio)) {
975 fprintf(fp, "%d\n", mUmsDirtyRatio);
976 } else {
977 SLOGE("Failed to read dirty_ratio (%s)", strerror(errno));
978 }
979 fclose(fp);
980 } else {
981 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
982 }
983 }
San Mehata2677e42009-12-13 10:40:18 -0800984 return 0;
985}
986
987int VolumeManager::unshareVolume(const char *label, const char *method) {
988 Volume *v = lookupVolume(label);
989
990 if (!v) {
991 errno = ENOENT;
992 return -1;
993 }
994
995 if (strcmp(method, "ums")) {
996 errno = ENOSYS;
997 return -1;
998 }
999
1000 if (v->getState() != Volume::State_Shared) {
1001 errno = EINVAL;
1002 return -1;
1003 }
1004
San Mehata2677e42009-12-13 10:40:18 -08001005 int fd;
Mike Lockwood97f2fc12011-06-07 10:51:38 -07001006 if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001007 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001008 return -1;
1009 }
1010
1011 char ch = 0;
1012 if (write(fd, &ch, 1) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001013 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001014 close(fd);
1015 return -1;
1016 }
1017
1018 close(fd);
1019 v->handleVolumeUnshared();
Mike Lockwooda28056b2010-10-28 15:21:24 -04001020 if (--mUmsSharingCount == 0 && mSavedDirtyRatio != -1) {
1021 FILE* fp;
1022 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1023 fprintf(fp, "%d\n", mSavedDirtyRatio);
1024 fclose(fp);
1025 } else {
1026 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1027 }
1028 mSavedDirtyRatio = -1;
1029 }
San Mehata2677e42009-12-13 10:40:18 -08001030 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -07001031}
1032
Ken Sumrall29d8da82011-05-18 17:20:07 -07001033extern "C" int vold_unmountVol(const char *label) {
1034 VolumeManager *vm = VolumeManager::Instance();
1035 return vm->unmountVolume(label, true);
1036}
1037
1038extern "C" int vold_getNumDirectVolumes(void) {
1039 VolumeManager *vm = VolumeManager::Instance();
1040 return vm->getNumDirectVolumes();
1041}
1042
1043int VolumeManager::getNumDirectVolumes(void) {
1044 VolumeCollection::iterator i;
1045 int n=0;
1046
1047 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1048 if ((*i)->getShareDevice() != (dev_t)0) {
1049 n++;
1050 }
1051 }
1052 return n;
1053}
1054
1055extern "C" int vold_getDirectVolumeList(struct volume_info *vol_list) {
1056 VolumeManager *vm = VolumeManager::Instance();
1057 return vm->getDirectVolumeList(vol_list);
1058}
1059
1060int VolumeManager::getDirectVolumeList(struct volume_info *vol_list) {
1061 VolumeCollection::iterator i;
1062 int n=0;
1063 dev_t d;
1064
1065 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1066 if ((d=(*i)->getShareDevice()) != (dev_t)0) {
1067 (*i)->getVolInfo(&vol_list[n]);
1068 snprintf(vol_list[n].blk_dev, sizeof(vol_list[n].blk_dev),
1069 "/dev/block/vold/%d:%d",MAJOR(d), MINOR(d));
1070 n++;
1071 }
1072 }
1073
1074 return 0;
1075}
1076
San Mehat4ba89482010-02-18 09:00:18 -08001077int VolumeManager::unmountVolume(const char *label, bool force) {
San Mehat49e2bce2009-10-12 16:29:01 -07001078 Volume *v = lookupVolume(label);
1079
1080 if (!v) {
1081 errno = ENOENT;
1082 return -1;
1083 }
1084
San Mehata2677e42009-12-13 10:40:18 -08001085 if (v->getState() == Volume::State_NoMedia) {
1086 errno = ENODEV;
1087 return -1;
1088 }
1089
San Mehat49e2bce2009-10-12 16:29:01 -07001090 if (v->getState() != Volume::State_Mounted) {
San Mehat97ac40e2010-03-24 10:24:19 -07001091 SLOGW("Attempt to unmount volume which isn't mounted (%d)\n",
San Mehata2677e42009-12-13 10:40:18 -08001092 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -07001093 errno = EBUSY;
Ken Sumrall319b1042011-06-14 14:01:55 -07001094 return UNMOUNT_NOT_MOUNTED_ERR;
San Mehat49e2bce2009-10-12 16:29:01 -07001095 }
1096
San Mehat1a06eda2010-04-15 12:58:50 -07001097 cleanupAsec(v, force);
San Mehat88705162010-01-15 09:26:28 -08001098
San Mehat4ba89482010-02-18 09:00:18 -08001099 return v->unmountVol(force);
San Mehat49e2bce2009-10-12 16:29:01 -07001100}
1101
San Mehata2677e42009-12-13 10:40:18 -08001102/*
1103 * Looks up a volume by it's label or mount-point
1104 */
San Mehat49e2bce2009-10-12 16:29:01 -07001105Volume *VolumeManager::lookupVolume(const char *label) {
1106 VolumeCollection::iterator i;
1107
1108 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -08001109 if (label[0] == '/') {
1110 if (!strcmp(label, (*i)->getMountpoint()))
1111 return (*i);
1112 } else {
1113 if (!strcmp(label, (*i)->getLabel()))
1114 return (*i);
1115 }
San Mehat49e2bce2009-10-12 16:29:01 -07001116 }
1117 return NULL;
1118}
San Mehata19b2502010-01-06 10:33:53 -08001119
1120bool VolumeManager::isMountpointMounted(const char *mp)
1121{
1122 char device[256];
1123 char mount_path[256];
1124 char rest[256];
1125 FILE *fp;
1126 char line[1024];
1127
1128 if (!(fp = fopen("/proc/mounts", "r"))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001129 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001130 return false;
1131 }
1132
1133 while(fgets(line, sizeof(line), fp)) {
1134 line[strlen(line)-1] = '\0';
1135 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1136 if (!strcmp(mount_path, mp)) {
1137 fclose(fp);
1138 return true;
1139 }
San Mehata19b2502010-01-06 10:33:53 -08001140 }
1141
1142 fclose(fp);
1143 return false;
1144}
1145
San Mehat1a06eda2010-04-15 12:58:50 -07001146int VolumeManager::cleanupAsec(Volume *v, bool force) {
1147 while(mActiveContainers->size()) {
1148 AsecIdCollection::iterator it = mActiveContainers->begin();
Kenny Rootcbacf782010-09-24 15:11:48 -07001149 ContainerData* cd = *it;
1150 SLOGI("Unmounting ASEC %s (dependant on %s)", cd->id, v->getMountpoint());
1151 if (cd->type == ASEC) {
1152 if (unmountAsec(cd->id, force)) {
1153 SLOGE("Failed to unmount ASEC %s (%s)", cd->id, strerror(errno));
1154 return -1;
1155 }
1156 } else if (cd->type == OBB) {
1157 if (unmountObb(cd->id, force)) {
1158 SLOGE("Failed to unmount OBB %s (%s)", cd->id, strerror(errno));
1159 return -1;
1160 }
1161 } else {
1162 SLOGE("Unknown container type %d!", cd->type);
San Mehat1a06eda2010-04-15 12:58:50 -07001163 return -1;
1164 }
1165 }
1166 return 0;
1167}
1168