blob: 88ac07ce66f1e83a460ded22b353ccb3cf38a8ad [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
San Mehat8b8f71b2010-01-11 09:17:25 -0800206int VolumeManager::createAsec(const char *id, unsigned int numSectors,
San Mehata19b2502010-01-06 10:33:53 -0800207 const char *fstype, const char *key, int ownerUid) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800208 struct asec_superblock sb;
209 memset(&sb, 0, sizeof(sb));
210
211 sb.magic = ASEC_SB_MAGIC;
212 sb.ver = ASEC_SB_VER;
San Mehata19b2502010-01-06 10:33:53 -0800213
San Mehatd31e3802010-02-18 08:37:45 -0800214 if (numSectors < ((1024*1024)/512)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700215 SLOGE("Invalid container size specified (%d sectors)", numSectors);
San Mehatd31e3802010-02-18 08:37:45 -0800216 errno = EINVAL;
217 return -1;
218 }
219
San Mehata19b2502010-01-06 10:33:53 -0800220 if (lookupVolume(id)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700221 SLOGE("ASEC id '%s' currently exists", id);
San Mehata19b2502010-01-06 10:33:53 -0800222 errno = EADDRINUSE;
223 return -1;
224 }
225
226 char asecFileName[255];
San Mehat3bb60202010-02-19 18:14:36 -0800227 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800228
229 if (!access(asecFileName, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700230 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
San Mehata19b2502010-01-06 10:33:53 -0800231 asecFileName, strerror(errno));
232 errno = EADDRINUSE;
233 return -1;
234 }
235
San Mehatfcf24fe2010-03-03 12:37:32 -0800236 /*
237 * Add some headroom
238 */
239 unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
240 unsigned numImgSectors = numSectors + fatSize + 2;
241
242 if (numImgSectors % 63) {
243 numImgSectors += (63 - (numImgSectors % 63));
244 }
245
246 // Add +1 for our superblock which is at the end
247 if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700248 SLOGE("ASEC image file creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800249 return -1;
250 }
251
San Mehatd9a4e352010-03-12 13:32:47 -0800252 char idHash[33];
253 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700254 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800255 unlink(asecFileName);
256 return -1;
257 }
258
San Mehata19b2502010-01-06 10:33:53 -0800259 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800260 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700261 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800262 unlink(asecFileName);
263 return -1;
264 }
265
San Mehatb78a32c2010-01-10 13:02:12 -0800266 char dmDevice[255];
267 bool cleanupDm = false;
San Mehata19b2502010-01-06 10:33:53 -0800268
San Mehatb78a32c2010-01-10 13:02:12 -0800269 if (strcmp(key, "none")) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800270 // XXX: This is all we support for now
271 sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
San Mehatd9a4e352010-03-12 13:32:47 -0800272 if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
San Mehatb78a32c2010-01-10 13:02:12 -0800273 sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700274 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800275 Loop::destroyByDevice(loopDevice);
276 unlink(asecFileName);
277 return -1;
278 }
279 cleanupDm = true;
280 } else {
San Mehatfcf24fe2010-03-03 12:37:32 -0800281 sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
San Mehatb78a32c2010-01-10 13:02:12 -0800282 strcpy(dmDevice, loopDevice);
283 }
284
San Mehatfcf24fe2010-03-03 12:37:32 -0800285 /*
286 * Drop down the superblock at the end of the file
287 */
288
289 int sbfd = open(loopDevice, O_RDWR);
290 if (sbfd < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700291 SLOGE("Failed to open new DM device for superblock write (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800292 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800293 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800294 }
295 Loop::destroyByDevice(loopDevice);
296 unlink(asecFileName);
297 return -1;
298 }
299
300 if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
301 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700302 SLOGE("Failed to lseek for superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800303 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800304 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800305 }
306 Loop::destroyByDevice(loopDevice);
307 unlink(asecFileName);
308 return -1;
309 }
310
311 if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) {
312 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700313 SLOGE("Failed to write superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800314 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800315 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800316 }
317 Loop::destroyByDevice(loopDevice);
318 unlink(asecFileName);
319 return -1;
320 }
321 close(sbfd);
322
San Mehata1091cb2010-02-28 20:17:20 -0800323 if (strcmp(fstype, "none")) {
324 if (strcmp(fstype, "fat")) {
San Mehat97ac40e2010-03-24 10:24:19 -0700325 SLOGW("Unknown fstype '%s' specified for container", fstype);
San Mehatb78a32c2010-01-10 13:02:12 -0800326 }
San Mehata19b2502010-01-06 10:33:53 -0800327
San Mehatfcf24fe2010-03-03 12:37:32 -0800328 if (Fat::format(dmDevice, numImgSectors)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700329 SLOGE("ASEC FAT format failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800330 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800331 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800332 }
San Mehateb13a902010-01-07 12:12:50 -0800333 Loop::destroyByDevice(loopDevice);
334 unlink(asecFileName);
335 return -1;
336 }
San Mehata1091cb2010-02-28 20:17:20 -0800337 char mountPoint[255];
San Mehata19b2502010-01-06 10:33:53 -0800338
San Mehata1091cb2010-02-28 20:17:20 -0800339 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
340 if (mkdir(mountPoint, 0777)) {
341 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -0700342 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800343 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800344 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800345 }
346 Loop::destroyByDevice(loopDevice);
347 unlink(asecFileName);
348 return -1;
349 }
San Mehatb78a32c2010-01-10 13:02:12 -0800350 }
San Mehata1091cb2010-02-28 20:17:20 -0800351
Kenny Roota3e06082010-08-27 08:31:35 -0700352 if (Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid,
San Mehata1091cb2010-02-28 20:17:20 -0800353 0, 0000, false)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700354 SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800355 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800356 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800357 }
358 Loop::destroyByDevice(loopDevice);
359 unlink(asecFileName);
360 return -1;
361 }
362 } else {
San Mehat97ac40e2010-03-24 10:24:19 -0700363 SLOGI("Created raw secure container %s (no filesystem)", id);
San Mehata19b2502010-01-06 10:33:53 -0800364 }
San Mehat88705162010-01-15 09:26:28 -0800365
Kenny Rootcbacf782010-09-24 15:11:48 -0700366 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehata19b2502010-01-06 10:33:53 -0800367 return 0;
368}
369
370int VolumeManager::finalizeAsec(const char *id) {
371 char asecFileName[255];
372 char loopDevice[255];
373 char mountPoint[255];
374
San Mehat3bb60202010-02-19 18:14:36 -0800375 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800376
San Mehatd9a4e352010-03-12 13:32:47 -0800377 char idHash[33];
378 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700379 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800380 return -1;
381 }
382
383 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700384 SLOGE("Unable to finalize %s (%s)", id, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800385 return -1;
386 }
387
San Mehat3bb60202010-02-19 18:14:36 -0800388 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatfff0b472010-01-06 19:19:46 -0800389 // XXX:
Kenny Roota3e06082010-08-27 08:31:35 -0700390 if (Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700391 SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800392 return -1;
393 }
394
San Mehatd9a4e352010-03-12 13:32:47 -0800395 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700396 SLOGD("ASEC %s finalized", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800397 }
San Mehata19b2502010-01-06 10:33:53 -0800398 return 0;
399}
400
San Mehat048b0802010-01-23 08:17:06 -0800401int VolumeManager::renameAsec(const char *id1, const char *id2) {
402 char *asecFilename1;
403 char *asecFilename2;
404 char mountPoint[255];
405
San Mehat3bb60202010-02-19 18:14:36 -0800406 asprintf(&asecFilename1, "%s/%s.asec", Volume::SEC_ASECDIR, id1);
407 asprintf(&asecFilename2, "%s/%s.asec", Volume::SEC_ASECDIR, id2);
San Mehat048b0802010-01-23 08:17:06 -0800408
San Mehat3bb60202010-02-19 18:14:36 -0800409 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
San Mehat048b0802010-01-23 08:17:06 -0800410 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700411 SLOGW("Rename attempt when src mounted");
San Mehat048b0802010-01-23 08:17:06 -0800412 errno = EBUSY;
413 goto out_err;
414 }
415
San Mehat96956ed2010-02-24 08:42:51 -0800416 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2);
417 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700418 SLOGW("Rename attempt when dst mounted");
San Mehat96956ed2010-02-24 08:42:51 -0800419 errno = EBUSY;
420 goto out_err;
421 }
422
San Mehat048b0802010-01-23 08:17:06 -0800423 if (!access(asecFilename2, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700424 SLOGE("Rename attempt when dst exists");
San Mehat048b0802010-01-23 08:17:06 -0800425 errno = EADDRINUSE;
426 goto out_err;
427 }
428
429 if (rename(asecFilename1, asecFilename2)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700430 SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
San Mehat048b0802010-01-23 08:17:06 -0800431 goto out_err;
432 }
433
434 free(asecFilename1);
435 free(asecFilename2);
436 return 0;
437
438out_err:
439 free(asecFilename1);
440 free(asecFilename2);
441 return -1;
442}
443
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700444#define UNMOUNT_RETRIES 5
445#define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
San Mehat4ba89482010-02-18 09:00:18 -0800446int VolumeManager::unmountAsec(const char *id, bool force) {
San Mehata19b2502010-01-06 10:33:53 -0800447 char asecFileName[255];
448 char mountPoint[255];
449
San Mehat3bb60202010-02-19 18:14:36 -0800450 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
451 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800452
San Mehatd9a4e352010-03-12 13:32:47 -0800453 char idHash[33];
454 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700455 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800456 return -1;
457 }
458
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700459 return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
460}
461
Kenny Root508c0e12010-07-12 09:59:49 -0700462int VolumeManager::unmountObb(const char *fileName, bool force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700463 char mountPoint[255];
464
465 char idHash[33];
466 if (!asecHash(fileName, idHash, sizeof(idHash))) {
467 SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
468 return -1;
469 }
470
471 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
472
473 return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
474}
475
476int VolumeManager::unmountLoopImage(const char *id, const char *idHash,
477 const char *fileName, const char *mountPoint, bool force) {
San Mehat0586d542010-01-12 15:38:59 -0800478 if (!isMountpointMounted(mountPoint)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700479 SLOGE("Unmount request for %s when not mounted", id);
Kenny Root918e5f92010-09-30 18:00:52 -0700480 errno = ENOENT;
San Mehatb78a32c2010-01-10 13:02:12 -0800481 return -1;
482 }
San Mehat23969932010-01-09 07:08:06 -0800483
San Mehatb78a32c2010-01-10 13:02:12 -0800484 int i, rc;
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700485 for (i = 1; i <= UNMOUNT_RETRIES; i++) {
San Mehatb78a32c2010-01-10 13:02:12 -0800486 rc = umount(mountPoint);
487 if (!rc) {
488 break;
San Mehata19b2502010-01-06 10:33:53 -0800489 }
San Mehatb78a32c2010-01-10 13:02:12 -0800490 if (rc && (errno == EINVAL || errno == ENOENT)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700491 SLOGI("Container %s unmounted OK", id);
San Mehatb78a32c2010-01-10 13:02:12 -0800492 rc = 0;
493 break;
San Mehata19b2502010-01-06 10:33:53 -0800494 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700495 SLOGW("%s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -0800496 id, i, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800497
San Mehat4ba89482010-02-18 09:00:18 -0800498 int action = 0; // default is to just complain
499
500 if (force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700501 if (i > (UNMOUNT_RETRIES - 2))
San Mehat4ba89482010-02-18 09:00:18 -0800502 action = 2; // SIGKILL
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700503 else if (i > (UNMOUNT_RETRIES - 3))
San Mehat4ba89482010-02-18 09:00:18 -0800504 action = 1; // SIGHUP
505 }
San Mehat8c940ef2010-02-13 14:19:53 -0800506
San Mehat586536c2010-02-16 17:12:00 -0800507 Process::killProcessesWithOpenFiles(mountPoint, action);
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700508 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehatb78a32c2010-01-10 13:02:12 -0800509 }
510
511 if (rc) {
San Mehat4ba89482010-02-18 09:00:18 -0800512 errno = EBUSY;
San Mehat97ac40e2010-03-24 10:24:19 -0700513 SLOGE("Failed to unmount container %s (%s)", id, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800514 return -1;
515 }
516
San Mehat12f4b892010-02-24 11:43:22 -0800517 int retries = 10;
518
519 while(retries--) {
520 if (!rmdir(mountPoint)) {
521 break;
522 }
523
San Mehat97ac40e2010-03-24 10:24:19 -0700524 SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700525 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehat12f4b892010-02-24 11:43:22 -0800526 }
527
528 if (!retries) {
San Mehat97ac40e2010-03-24 10:24:19 -0700529 SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
San Mehatf5c61982010-02-03 11:04:46 -0800530 }
San Mehat88705162010-01-15 09:26:28 -0800531
San Mehatd9a4e352010-03-12 13:32:47 -0800532 if (Devmapper::destroy(idHash) && errno != ENXIO) {
San Mehat97ac40e2010-03-24 10:24:19 -0700533 SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800534 }
535
536 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800537 if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800538 Loop::destroyByDevice(loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800539 } else {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700540 SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800541 }
San Mehat88705162010-01-15 09:26:28 -0800542
543 AsecIdCollection::iterator it;
544 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
Kenny Rootcbacf782010-09-24 15:11:48 -0700545 ContainerData* cd = *it;
546 if (!strcmp(cd->id, id)) {
San Mehat88705162010-01-15 09:26:28 -0800547 free(*it);
548 mActiveContainers->erase(it);
549 break;
550 }
551 }
552 if (it == mActiveContainers->end()) {
San Mehat97ac40e2010-03-24 10:24:19 -0700553 SLOGW("mActiveContainers is inconsistent!");
San Mehat88705162010-01-15 09:26:28 -0800554 }
San Mehatb78a32c2010-01-10 13:02:12 -0800555 return 0;
556}
557
San Mehat4ba89482010-02-18 09:00:18 -0800558int VolumeManager::destroyAsec(const char *id, bool force) {
San Mehatb78a32c2010-01-10 13:02:12 -0800559 char asecFileName[255];
560 char mountPoint[255];
561
San Mehat3bb60202010-02-19 18:14:36 -0800562 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehat55013f72010-02-24 12:12:34 -0800563 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatb78a32c2010-01-10 13:02:12 -0800564
San Mehat0586d542010-01-12 15:38:59 -0800565 if (isMountpointMounted(mountPoint)) {
San Mehatd9a4e352010-03-12 13:32:47 -0800566 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700567 SLOGD("Unmounting container before destroy");
San Mehatd9a4e352010-03-12 13:32:47 -0800568 }
San Mehat4ba89482010-02-18 09:00:18 -0800569 if (unmountAsec(id, force)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700570 SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800571 return -1;
572 }
573 }
San Mehata19b2502010-01-06 10:33:53 -0800574
San Mehat0586d542010-01-12 15:38:59 -0800575 if (unlink(asecFileName)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700576 SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800577 return -1;
578 }
San Mehata19b2502010-01-06 10:33:53 -0800579
San Mehatd9a4e352010-03-12 13:32:47 -0800580 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700581 SLOGD("ASEC %s destroyed", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800582 }
San Mehata19b2502010-01-06 10:33:53 -0800583 return 0;
584}
585
586int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
587 char asecFileName[255];
588 char mountPoint[255];
589
San Mehat3bb60202010-02-19 18:14:36 -0800590 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
591 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800592
593 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700594 SLOGE("ASEC %s already mounted", id);
San Mehata19b2502010-01-06 10:33:53 -0800595 errno = EBUSY;
596 return -1;
597 }
598
San Mehatd9a4e352010-03-12 13:32:47 -0800599 char idHash[33];
600 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700601 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800602 return -1;
603 }
Kenny Root7b18a7b2010-03-15 13:13:41 -0700604
San Mehata19b2502010-01-06 10:33:53 -0800605 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800606 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
607 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700608 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800609 return -1;
610 }
San Mehatd9a4e352010-03-12 13:32:47 -0800611 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700612 SLOGD("New loop device created at %s", loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800613 }
San Mehatb78a32c2010-01-10 13:02:12 -0800614 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800615 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700616 SLOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800617 }
San Mehatb78a32c2010-01-10 13:02:12 -0800618 }
619
620 char dmDevice[255];
621 bool cleanupDm = false;
San Mehatfcf24fe2010-03-03 12:37:32 -0800622 int fd;
623 unsigned int nr_sec = 0;
624
625 if ((fd = open(loopDevice, O_RDWR)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700626 SLOGE("Failed to open loopdevice (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800627 Loop::destroyByDevice(loopDevice);
628 return -1;
629 }
630
631 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700632 SLOGE("Failed to get loop size (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800633 Loop::destroyByDevice(loopDevice);
634 close(fd);
635 return -1;
636 }
637
638 /*
639 * Validate superblock
640 */
641 struct asec_superblock sb;
642 memset(&sb, 0, sizeof(sb));
643 if (lseek(fd, ((nr_sec-1) * 512), SEEK_SET) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700644 SLOGE("lseek failed (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800645 close(fd);
646 Loop::destroyByDevice(loopDevice);
647 return -1;
648 }
649 if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700650 SLOGE("superblock read failed (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800651 close(fd);
652 Loop::destroyByDevice(loopDevice);
653 return -1;
654 }
655
656 close(fd);
657
San Mehatd9a4e352010-03-12 13:32:47 -0800658 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700659 SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatd9a4e352010-03-12 13:32:47 -0800660 }
San Mehatfcf24fe2010-03-03 12:37:32 -0800661 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
San Mehat97ac40e2010-03-24 10:24:19 -0700662 SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatfcf24fe2010-03-03 12:37:32 -0800663 Loop::destroyByDevice(loopDevice);
664 errno = EMEDIUMTYPE;
665 return -1;
666 }
667 nr_sec--; // We don't want the devmapping to extend onto our superblock
668
San Mehatb78a32c2010-01-10 13:02:12 -0800669 if (strcmp(key, "none")) {
San Mehatd9a4e352010-03-12 13:32:47 -0800670 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
671 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
San Mehatb78a32c2010-01-10 13:02:12 -0800672 dmDevice, sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700673 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800674 Loop::destroyByDevice(loopDevice);
675 return -1;
676 }
San Mehatd9a4e352010-03-12 13:32:47 -0800677 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700678 SLOGD("New devmapper instance created at %s", dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800679 }
San Mehatb78a32c2010-01-10 13:02:12 -0800680 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800681 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700682 SLOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800683 }
San Mehatb78a32c2010-01-10 13:02:12 -0800684 }
685 cleanupDm = true;
686 } else {
687 strcpy(dmDevice, loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800688 }
689
690 if (mkdir(mountPoint, 0777)) {
San Mehatb78a32c2010-01-10 13:02:12 -0800691 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -0700692 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800693 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800694 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800695 }
696 Loop::destroyByDevice(loopDevice);
697 return -1;
698 }
San Mehata19b2502010-01-06 10:33:53 -0800699 }
700
Kenny Roota3e06082010-08-27 08:31:35 -0700701 if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0,
San Mehatcff5ec32010-01-08 12:31:44 -0800702 0222, false)) {
703// 0227, false)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700704 SLOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800705 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800706 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800707 }
708 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800709 return -1;
710 }
711
Kenny Rootcbacf782010-09-24 15:11:48 -0700712 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehatd9a4e352010-03-12 13:32:47 -0800713 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700714 SLOGD("ASEC %s mounted", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800715 }
San Mehata19b2502010-01-06 10:33:53 -0800716 return 0;
717}
718
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700719/**
720 * Mounts an image file <code>img</code>.
721 */
Kenny Root508c0e12010-07-12 09:59:49 -0700722int VolumeManager::mountObb(const char *img, const char *key, int ownerUid) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700723 char mountPoint[255];
724
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700725 char idHash[33];
726 if (!asecHash(img, idHash, sizeof(idHash))) {
727 SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
728 return -1;
729 }
730
731 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
732
733 if (isMountpointMounted(mountPoint)) {
734 SLOGE("Image %s already mounted", img);
735 errno = EBUSY;
736 return -1;
737 }
738
739 char loopDevice[255];
740 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
741 if (Loop::create(idHash, img, loopDevice, sizeof(loopDevice))) {
742 SLOGE("Image loop device creation failed (%s)", strerror(errno));
743 return -1;
744 }
745 if (mDebug) {
746 SLOGD("New loop device created at %s", loopDevice);
747 }
748 } else {
749 if (mDebug) {
750 SLOGD("Found active loopback for %s at %s", img, loopDevice);
751 }
752 }
753
754 char dmDevice[255];
755 bool cleanupDm = false;
756 int fd;
757 unsigned int nr_sec = 0;
758
759 if ((fd = open(loopDevice, O_RDWR)) < 0) {
760 SLOGE("Failed to open loopdevice (%s)", strerror(errno));
761 Loop::destroyByDevice(loopDevice);
762 return -1;
763 }
764
765 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
766 SLOGE("Failed to get loop size (%s)", strerror(errno));
767 Loop::destroyByDevice(loopDevice);
768 close(fd);
769 return -1;
770 }
771
772 close(fd);
773
774 if (strcmp(key, "none")) {
775 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
776 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
777 dmDevice, sizeof(dmDevice))) {
778 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
779 Loop::destroyByDevice(loopDevice);
780 return -1;
781 }
782 if (mDebug) {
783 SLOGD("New devmapper instance created at %s", dmDevice);
784 }
785 } else {
786 if (mDebug) {
787 SLOGD("Found active devmapper for %s at %s", img, dmDevice);
788 }
789 }
790 cleanupDm = true;
791 } else {
792 strcpy(dmDevice, loopDevice);
793 }
794
795 if (mkdir(mountPoint, 0755)) {
796 if (errno != EEXIST) {
797 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
798 if (cleanupDm) {
799 Devmapper::destroy(idHash);
800 }
801 Loop::destroyByDevice(loopDevice);
802 return -1;
803 }
804 }
805
Kenny Roota3e06082010-08-27 08:31:35 -0700806 if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0,
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700807 0227, false)) {
808 SLOGE("Image mount failed (%s)", strerror(errno));
809 if (cleanupDm) {
810 Devmapper::destroy(idHash);
811 }
812 Loop::destroyByDevice(loopDevice);
813 return -1;
814 }
815
Kenny Rootcbacf782010-09-24 15:11:48 -0700816 mActiveContainers->push_back(new ContainerData(strdup(img), OBB));
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700817 if (mDebug) {
818 SLOGD("Image %s mounted", img);
819 }
820 return 0;
821}
822
San Mehat49e2bce2009-10-12 16:29:01 -0700823int VolumeManager::mountVolume(const char *label) {
824 Volume *v = lookupVolume(label);
825
826 if (!v) {
827 errno = ENOENT;
828 return -1;
829 }
830
San Mehata2677e42009-12-13 10:40:18 -0800831 return v->mountVol();
832}
833
Kenny Root508c0e12010-07-12 09:59:49 -0700834int VolumeManager::listMountedObbs(SocketClient* cli) {
835 char device[256];
836 char mount_path[256];
837 char rest[256];
838 FILE *fp;
839 char line[1024];
840
841 if (!(fp = fopen("/proc/mounts", "r"))) {
842 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
843 return -1;
844 }
845
846 // Create a string to compare against that has a trailing slash
847 int loopDirLen = sizeof(Volume::LOOPDIR);
848 char loopDir[loopDirLen + 2];
849 strcpy(loopDir, Volume::LOOPDIR);
850 loopDir[loopDirLen++] = '/';
851 loopDir[loopDirLen] = '\0';
852
853 while(fgets(line, sizeof(line), fp)) {
854 line[strlen(line)-1] = '\0';
855
856 /*
857 * Should look like:
858 * /dev/block/loop0 /mnt/obb/fc99df1323fd36424f864dcb76b76d65 ...
859 */
860 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
861
862 if (!strncmp(mount_path, loopDir, loopDirLen)) {
863 int fd = open(device, O_RDONLY);
864 if (fd >= 0) {
865 struct loop_info64 li;
866 if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
867 cli->sendMsg(ResponseCode::AsecListResult,
868 (const char*) li.lo_file_name, false);
869 }
870 close(fd);
871 }
872 }
873 }
874
875 fclose(fp);
876 return 0;
877}
878
San Mehateba65e92010-01-29 05:15:16 -0800879int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
880 Volume *v = lookupVolume(label);
881
882 if (!v) {
883 errno = ENOENT;
884 return -1;
885 }
886
887 if (strcmp(method, "ums")) {
888 errno = ENOSYS;
889 return -1;
890 }
891
892 if (v->getState() != Volume::State_Shared) {
San Mehateba65e92010-01-29 05:15:16 -0800893 *enabled = false;
San Mehatb9aed742010-02-04 15:07:01 -0800894 } else {
895 *enabled = true;
San Mehateba65e92010-01-29 05:15:16 -0800896 }
897 return 0;
898}
899
San Mehata2677e42009-12-13 10:40:18 -0800900int VolumeManager::shareVolume(const char *label, const char *method) {
901 Volume *v = lookupVolume(label);
902
903 if (!v) {
904 errno = ENOENT;
905 return -1;
906 }
907
908 /*
909 * Eventually, we'll want to support additional share back-ends,
910 * some of which may work while the media is mounted. For now,
911 * we just support UMS
912 */
913 if (strcmp(method, "ums")) {
914 errno = ENOSYS;
915 return -1;
916 }
917
918 if (v->getState() == Volume::State_NoMedia) {
919 errno = ENODEV;
920 return -1;
921 }
922
San Mehat49e2bce2009-10-12 16:29:01 -0700923 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -0800924 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -0700925 errno = EBUSY;
926 return -1;
927 }
928
Mike Lockwood2dfe2972010-09-17 18:50:51 -0400929 dev_t d = v->getShareDevice();
San Mehata2677e42009-12-13 10:40:18 -0800930 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
931 // This volume does not support raw disk access
932 errno = EINVAL;
933 return -1;
934 }
935
936 int fd;
937 char nodepath[255];
938 snprintf(nodepath,
939 sizeof(nodepath), "/dev/block/vold/%d:%d",
940 MAJOR(d), MINOR(d));
941
Mike Lockwood97f2fc12011-06-07 10:51:38 -0700942 if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700943 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -0800944 return -1;
945 }
946
947 if (write(fd, nodepath, strlen(nodepath)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700948 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -0800949 close(fd);
950 return -1;
951 }
952
953 close(fd);
954 v->handleVolumeShared();
Mike Lockwooda28056b2010-10-28 15:21:24 -0400955 if (mUmsSharingCount++ == 0) {
956 FILE* fp;
957 mSavedDirtyRatio = -1; // in case we fail
958 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
959 char line[16];
960 if (fgets(line, sizeof(line), fp) && sscanf(line, "%d", &mSavedDirtyRatio)) {
961 fprintf(fp, "%d\n", mUmsDirtyRatio);
962 } else {
963 SLOGE("Failed to read dirty_ratio (%s)", strerror(errno));
964 }
965 fclose(fp);
966 } else {
967 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
968 }
969 }
San Mehata2677e42009-12-13 10:40:18 -0800970 return 0;
971}
972
973int VolumeManager::unshareVolume(const char *label, const char *method) {
974 Volume *v = lookupVolume(label);
975
976 if (!v) {
977 errno = ENOENT;
978 return -1;
979 }
980
981 if (strcmp(method, "ums")) {
982 errno = ENOSYS;
983 return -1;
984 }
985
986 if (v->getState() != Volume::State_Shared) {
987 errno = EINVAL;
988 return -1;
989 }
990
San Mehata2677e42009-12-13 10:40:18 -0800991 int fd;
Mike Lockwood97f2fc12011-06-07 10:51:38 -0700992 if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700993 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -0800994 return -1;
995 }
996
997 char ch = 0;
998 if (write(fd, &ch, 1) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700999 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001000 close(fd);
1001 return -1;
1002 }
1003
1004 close(fd);
1005 v->handleVolumeUnshared();
Mike Lockwooda28056b2010-10-28 15:21:24 -04001006 if (--mUmsSharingCount == 0 && mSavedDirtyRatio != -1) {
1007 FILE* fp;
1008 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1009 fprintf(fp, "%d\n", mSavedDirtyRatio);
1010 fclose(fp);
1011 } else {
1012 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1013 }
1014 mSavedDirtyRatio = -1;
1015 }
San Mehata2677e42009-12-13 10:40:18 -08001016 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -07001017}
1018
Ken Sumrall29d8da82011-05-18 17:20:07 -07001019extern "C" int vold_unmountVol(const char *label) {
1020 VolumeManager *vm = VolumeManager::Instance();
1021 return vm->unmountVolume(label, true);
1022}
1023
1024extern "C" int vold_getNumDirectVolumes(void) {
1025 VolumeManager *vm = VolumeManager::Instance();
1026 return vm->getNumDirectVolumes();
1027}
1028
1029int VolumeManager::getNumDirectVolumes(void) {
1030 VolumeCollection::iterator i;
1031 int n=0;
1032
1033 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1034 if ((*i)->getShareDevice() != (dev_t)0) {
1035 n++;
1036 }
1037 }
1038 return n;
1039}
1040
1041extern "C" int vold_getDirectVolumeList(struct volume_info *vol_list) {
1042 VolumeManager *vm = VolumeManager::Instance();
1043 return vm->getDirectVolumeList(vol_list);
1044}
1045
1046int VolumeManager::getDirectVolumeList(struct volume_info *vol_list) {
1047 VolumeCollection::iterator i;
1048 int n=0;
1049 dev_t d;
1050
1051 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1052 if ((d=(*i)->getShareDevice()) != (dev_t)0) {
1053 (*i)->getVolInfo(&vol_list[n]);
1054 snprintf(vol_list[n].blk_dev, sizeof(vol_list[n].blk_dev),
1055 "/dev/block/vold/%d:%d",MAJOR(d), MINOR(d));
1056 n++;
1057 }
1058 }
1059
1060 return 0;
1061}
1062
San Mehat4ba89482010-02-18 09:00:18 -08001063int VolumeManager::unmountVolume(const char *label, bool force) {
San Mehat49e2bce2009-10-12 16:29:01 -07001064 Volume *v = lookupVolume(label);
1065
1066 if (!v) {
1067 errno = ENOENT;
1068 return -1;
1069 }
1070
San Mehata2677e42009-12-13 10:40:18 -08001071 if (v->getState() == Volume::State_NoMedia) {
1072 errno = ENODEV;
1073 return -1;
1074 }
1075
San Mehat49e2bce2009-10-12 16:29:01 -07001076 if (v->getState() != Volume::State_Mounted) {
San Mehat97ac40e2010-03-24 10:24:19 -07001077 SLOGW("Attempt to unmount volume which isn't mounted (%d)\n",
San Mehata2677e42009-12-13 10:40:18 -08001078 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -07001079 errno = EBUSY;
Ken Sumrall319b1042011-06-14 14:01:55 -07001080 return UNMOUNT_NOT_MOUNTED_ERR;
San Mehat49e2bce2009-10-12 16:29:01 -07001081 }
1082
San Mehat1a06eda2010-04-15 12:58:50 -07001083 cleanupAsec(v, force);
San Mehat88705162010-01-15 09:26:28 -08001084
San Mehat4ba89482010-02-18 09:00:18 -08001085 return v->unmountVol(force);
San Mehat49e2bce2009-10-12 16:29:01 -07001086}
1087
San Mehata2677e42009-12-13 10:40:18 -08001088/*
1089 * Looks up a volume by it's label or mount-point
1090 */
San Mehat49e2bce2009-10-12 16:29:01 -07001091Volume *VolumeManager::lookupVolume(const char *label) {
1092 VolumeCollection::iterator i;
1093
1094 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -08001095 if (label[0] == '/') {
1096 if (!strcmp(label, (*i)->getMountpoint()))
1097 return (*i);
1098 } else {
1099 if (!strcmp(label, (*i)->getLabel()))
1100 return (*i);
1101 }
San Mehat49e2bce2009-10-12 16:29:01 -07001102 }
1103 return NULL;
1104}
San Mehata19b2502010-01-06 10:33:53 -08001105
1106bool VolumeManager::isMountpointMounted(const char *mp)
1107{
1108 char device[256];
1109 char mount_path[256];
1110 char rest[256];
1111 FILE *fp;
1112 char line[1024];
1113
1114 if (!(fp = fopen("/proc/mounts", "r"))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001115 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001116 return false;
1117 }
1118
1119 while(fgets(line, sizeof(line), fp)) {
1120 line[strlen(line)-1] = '\0';
1121 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1122 if (!strcmp(mount_path, mp)) {
1123 fclose(fp);
1124 return true;
1125 }
San Mehata19b2502010-01-06 10:33:53 -08001126 }
1127
1128 fclose(fp);
1129 return false;
1130}
1131
San Mehat1a06eda2010-04-15 12:58:50 -07001132int VolumeManager::cleanupAsec(Volume *v, bool force) {
1133 while(mActiveContainers->size()) {
1134 AsecIdCollection::iterator it = mActiveContainers->begin();
Kenny Rootcbacf782010-09-24 15:11:48 -07001135 ContainerData* cd = *it;
1136 SLOGI("Unmounting ASEC %s (dependant on %s)", cd->id, v->getMountpoint());
1137 if (cd->type == ASEC) {
1138 if (unmountAsec(cd->id, force)) {
1139 SLOGE("Failed to unmount ASEC %s (%s)", cd->id, strerror(errno));
1140 return -1;
1141 }
1142 } else if (cd->type == OBB) {
1143 if (unmountObb(cd->id, force)) {
1144 SLOGE("Failed to unmount OBB %s (%s)", cd->id, strerror(errno));
1145 return -1;
1146 }
1147 } else {
1148 SLOGE("Unknown container type %d!", cd->type);
San Mehat1a06eda2010-04-15 12:58:50 -07001149 return -1;
1150 }
1151 }
1152 return 0;
1153}
1154