blob: bdc77396dcc2de3dead3c4d204cb41618447ee01 [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>
Kenny Root344ca102012-04-03 17:23:01 -070022#include <fts.h>
23#include <unistd.h>
San Mehata19b2502010-01-06 10:33:53 -080024#include <sys/stat.h>
25#include <sys/types.h>
26#include <sys/mount.h>
Ken Sumrall425524d2012-06-14 20:55:28 -070027#include <dirent.h>
San Mehata19b2502010-01-06 10:33:53 -080028
San Mehata2677e42009-12-13 10:40:18 -080029#include <linux/kdev_t.h>
San Mehatf1b736b2009-10-10 17:22:08 -070030
31#define LOG_TAG "Vold"
32
Kenny Root7b18a7b2010-03-15 13:13:41 -070033#include <openssl/md5.h>
34
San Mehatf1b736b2009-10-10 17:22:08 -070035#include <cutils/log.h>
36
San Mehatfd7f5872009-10-12 11:32:47 -070037#include <sysutils/NetlinkEvent.h>
38
Kenny Root344ca102012-04-03 17:23:01 -070039#include <private/android_filesystem_config.h>
40
San Mehatf1b736b2009-10-10 17:22:08 -070041#include "VolumeManager.h"
San Mehatae10b912009-10-12 14:57:05 -070042#include "DirectVolume.h"
San Mehata2677e42009-12-13 10:40:18 -080043#include "ResponseCode.h"
San Mehata19b2502010-01-06 10:33:53 -080044#include "Loop.h"
Kenny Root344ca102012-04-03 17:23:01 -070045#include "Ext4.h"
San Mehata19b2502010-01-06 10:33:53 -080046#include "Fat.h"
San Mehatb78a32c2010-01-10 13:02:12 -080047#include "Devmapper.h"
San Mehat586536c2010-02-16 17:12:00 -080048#include "Process.h"
San Mehatfcf24fe2010-03-03 12:37:32 -080049#include "Asec.h"
Ken Sumrall29d8da82011-05-18 17:20:07 -070050#include "cryptfs.h"
San Mehat23969932010-01-09 07:08:06 -080051
Mike Lockwood97f2fc12011-06-07 10:51:38 -070052#define MASS_STORAGE_FILE_PATH "/sys/class/android_usb/android0/f_mass_storage/lun/file"
53
San Mehatf1b736b2009-10-10 17:22:08 -070054VolumeManager *VolumeManager::sInstance = NULL;
55
56VolumeManager *VolumeManager::Instance() {
57 if (!sInstance)
58 sInstance = new VolumeManager();
59 return sInstance;
60}
61
62VolumeManager::VolumeManager() {
San Mehatd9a4e352010-03-12 13:32:47 -080063 mDebug = false;
San Mehatf1b736b2009-10-10 17:22:08 -070064 mVolumes = new VolumeCollection();
San Mehat88705162010-01-15 09:26:28 -080065 mActiveContainers = new AsecIdCollection();
San Mehatf1b736b2009-10-10 17:22:08 -070066 mBroadcaster = NULL;
Mike Lockwooda28056b2010-10-28 15:21:24 -040067 mUmsSharingCount = 0;
68 mSavedDirtyRatio = -1;
69 // set dirty ratio to 0 when UMS is active
70 mUmsDirtyRatio = 0;
Ken Sumrall3b170052011-07-11 15:38:57 -070071 mVolManagerDisabled = 0;
San Mehatf1b736b2009-10-10 17:22:08 -070072}
73
74VolumeManager::~VolumeManager() {
San Mehat88705162010-01-15 09:26:28 -080075 delete mVolumes;
76 delete mActiveContainers;
San Mehatf1b736b2009-10-10 17:22:08 -070077}
78
Kenny Root7b18a7b2010-03-15 13:13:41 -070079char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -070080 static const char* digits = "0123456789abcdef";
81
Kenny Root7b18a7b2010-03-15 13:13:41 -070082 unsigned char sig[MD5_DIGEST_LENGTH];
83
Kenny Rootacc9e7d2010-06-18 19:06:50 -070084 if (buffer == NULL) {
85 SLOGE("Destination buffer is NULL");
86 errno = ESPIPE;
87 return NULL;
88 } else if (id == NULL) {
89 SLOGE("Source buffer is NULL");
90 errno = ESPIPE;
91 return NULL;
92 } else if (len < MD5_ASCII_LENGTH_PLUS_NULL) {
93 SLOGE("Target hash buffer size < %d bytes (%d)",
94 MD5_ASCII_LENGTH_PLUS_NULL, len);
San Mehatd9a4e352010-03-12 13:32:47 -080095 errno = ESPIPE;
96 return NULL;
97 }
Kenny Root7b18a7b2010-03-15 13:13:41 -070098
99 MD5(reinterpret_cast<const unsigned char*>(id), strlen(id), sig);
San Mehatd9a4e352010-03-12 13:32:47 -0800100
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700101 char *p = buffer;
Kenny Root7b18a7b2010-03-15 13:13:41 -0700102 for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700103 *p++ = digits[sig[i] >> 4];
104 *p++ = digits[sig[i] & 0x0F];
San Mehatd9a4e352010-03-12 13:32:47 -0800105 }
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700106 *p = '\0';
San Mehatd9a4e352010-03-12 13:32:47 -0800107
108 return buffer;
109}
110
111void VolumeManager::setDebug(bool enable) {
112 mDebug = enable;
113 VolumeCollection::iterator it;
114 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
115 (*it)->setDebug(enable);
116 }
117}
118
San Mehatf1b736b2009-10-10 17:22:08 -0700119int VolumeManager::start() {
120 return 0;
121}
122
123int VolumeManager::stop() {
124 return 0;
125}
126
127int VolumeManager::addVolume(Volume *v) {
128 mVolumes->push_back(v);
129 return 0;
130}
131
San Mehatfd7f5872009-10-12 11:32:47 -0700132void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
133 const char *devpath = evt->findParam("DEVPATH");
San Mehatf1b736b2009-10-10 17:22:08 -0700134
San Mehatfd7f5872009-10-12 11:32:47 -0700135 /* Lookup a volume to handle this device */
San Mehatf1b736b2009-10-10 17:22:08 -0700136 VolumeCollection::iterator it;
137 bool hit = false;
138 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
San Mehatfd7f5872009-10-12 11:32:47 -0700139 if (!(*it)->handleBlockEvent(evt)) {
San Mehata2677e42009-12-13 10:40:18 -0800140#ifdef NETLINK_DEBUG
San Mehat97ac40e2010-03-24 10:24:19 -0700141 SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
San Mehata2677e42009-12-13 10:40:18 -0800142#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700143 hit = true;
San Mehatf1b736b2009-10-10 17:22:08 -0700144 break;
145 }
146 }
147
148 if (!hit) {
San Mehata2677e42009-12-13 10:40:18 -0800149#ifdef NETLINK_DEBUG
San Mehat97ac40e2010-03-24 10:24:19 -0700150 SLOGW("No volumes handled block event for '%s'", devpath);
San Mehata2677e42009-12-13 10:40:18 -0800151#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700152 }
153}
154
San Mehatf1b736b2009-10-10 17:22:08 -0700155int VolumeManager::listVolumes(SocketClient *cli) {
156 VolumeCollection::iterator i;
157
158 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
159 char *buffer;
160 asprintf(&buffer, "%s %s %d",
161 (*i)->getLabel(), (*i)->getMountpoint(),
162 (*i)->getState());
San Mehata2677e42009-12-13 10:40:18 -0800163 cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
San Mehatf1b736b2009-10-10 17:22:08 -0700164 free(buffer);
165 }
San Mehata2677e42009-12-13 10:40:18 -0800166 cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
San Mehatf1b736b2009-10-10 17:22:08 -0700167 return 0;
168}
San Mehat49e2bce2009-10-12 16:29:01 -0700169
San Mehata2677e42009-12-13 10:40:18 -0800170int VolumeManager::formatVolume(const char *label) {
171 Volume *v = lookupVolume(label);
172
173 if (!v) {
174 errno = ENOENT;
175 return -1;
176 }
177
Ken Sumrall3b170052011-07-11 15:38:57 -0700178 if (mVolManagerDisabled) {
179 errno = EBUSY;
180 return -1;
181 }
182
San Mehata2677e42009-12-13 10:40:18 -0800183 return v->formatVol();
184}
185
Kenny Root508c0e12010-07-12 09:59:49 -0700186int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) {
187 char idHash[33];
188 if (!asecHash(sourceFile, idHash, sizeof(idHash))) {
189 SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno));
190 return -1;
191 }
192
193 memset(mountPath, 0, mountPathLen);
rpcraigd1c226f2012-10-09 06:58:16 -0400194 int written = snprintf(mountPath, mountPathLen, "%s/%s", Volume::LOOPDIR, idHash);
195 if ((written < 0) || (written >= mountPathLen)) {
196 errno = EINVAL;
197 return -1;
198 }
Kenny Root508c0e12010-07-12 09:59:49 -0700199
200 if (access(mountPath, F_OK)) {
201 errno = ENOENT;
202 return -1;
203 }
204
205 return 0;
206}
207
San Mehata19b2502010-01-06 10:33:53 -0800208int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
San Mehat88ac2c02010-03-23 11:15:58 -0700209 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700210
211 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
212 SLOGE("Couldn't find ASEC %s", id);
213 return -1;
214 }
San Mehat88ac2c02010-03-23 11:15:58 -0700215
216 memset(buffer, 0, maxlen);
217 if (access(asecFileName, F_OK)) {
218 errno = ENOENT;
219 return -1;
220 }
San Mehata19b2502010-01-06 10:33:53 -0800221
rpcraigd1c226f2012-10-09 06:58:16 -0400222 int written = snprintf(buffer, maxlen, "%s/%s", Volume::ASECDIR, id);
223 if ((written < 0) || (written >= maxlen)) {
224 SLOGE("getAsecMountPath failed for %s: couldn't construct path in buffer", id);
225 errno = EINVAL;
226 return -1;
227 }
228
San Mehata19b2502010-01-06 10:33:53 -0800229 return 0;
230}
231
Dianne Hackborn736910c2011-06-27 13:37:07 -0700232int VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxlen) {
233 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700234
235 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
236 SLOGE("Couldn't find ASEC %s", id);
237 return -1;
238 }
Dianne Hackborn736910c2011-06-27 13:37:07 -0700239
240 memset(buffer, 0, maxlen);
241 if (access(asecFileName, F_OK)) {
242 errno = ENOENT;
243 return -1;
244 }
245
rpcraigd1c226f2012-10-09 06:58:16 -0400246 int written = snprintf(buffer, maxlen, "%s", asecFileName);
247 if ((written < 0) || (written >= maxlen)) {
248 errno = EINVAL;
249 return -1;
250 }
251
Dianne Hackborn736910c2011-06-27 13:37:07 -0700252 return 0;
253}
254
Kenny Root344ca102012-04-03 17:23:01 -0700255int VolumeManager::createAsec(const char *id, unsigned int numSectors, const char *fstype,
256 const char *key, const int ownerUid, bool isExternal) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800257 struct asec_superblock sb;
258 memset(&sb, 0, sizeof(sb));
259
Kenny Root344ca102012-04-03 17:23:01 -0700260 const bool wantFilesystem = strcmp(fstype, "none");
261 bool usingExt4 = false;
262 if (wantFilesystem) {
263 usingExt4 = !strcmp(fstype, "ext4");
264 if (usingExt4) {
265 sb.c_opts |= ASEC_SB_C_OPTS_EXT4;
266 } else if (strcmp(fstype, "fat")) {
267 SLOGE("Invalid filesystem type %s", fstype);
268 errno = EINVAL;
269 return -1;
270 }
271 }
272
San Mehatfcf24fe2010-03-03 12:37:32 -0800273 sb.magic = ASEC_SB_MAGIC;
274 sb.ver = ASEC_SB_VER;
San Mehata19b2502010-01-06 10:33:53 -0800275
San Mehatd31e3802010-02-18 08:37:45 -0800276 if (numSectors < ((1024*1024)/512)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700277 SLOGE("Invalid container size specified (%d sectors)", numSectors);
San Mehatd31e3802010-02-18 08:37:45 -0800278 errno = EINVAL;
279 return -1;
280 }
281
San Mehata19b2502010-01-06 10:33:53 -0800282 if (lookupVolume(id)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700283 SLOGE("ASEC id '%s' currently exists", id);
San Mehata19b2502010-01-06 10:33:53 -0800284 errno = EADDRINUSE;
285 return -1;
286 }
287
288 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700289
290 if (!findAsec(id, asecFileName, sizeof(asecFileName))) {
291 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
292 asecFileName, strerror(errno));
293 errno = EADDRINUSE;
294 return -1;
295 }
296
297 const char *asecDir = isExternal ? Volume::SEC_ASECDIR_EXT : Volume::SEC_ASECDIR_INT;
298
rpcraigd1c226f2012-10-09 06:58:16 -0400299 int written = snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", asecDir, id);
300 if ((written < 0) || (size_t(written) >= sizeof(asecFileName))) {
301 errno = EINVAL;
302 return -1;
303 }
San Mehata19b2502010-01-06 10:33:53 -0800304
305 if (!access(asecFileName, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700306 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
Kenny Root344ca102012-04-03 17:23:01 -0700307 asecFileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800308 errno = EADDRINUSE;
309 return -1;
310 }
311
San Mehatfcf24fe2010-03-03 12:37:32 -0800312 /*
313 * Add some headroom
314 */
315 unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
316 unsigned numImgSectors = numSectors + fatSize + 2;
317
318 if (numImgSectors % 63) {
319 numImgSectors += (63 - (numImgSectors % 63));
320 }
321
322 // Add +1 for our superblock which is at the end
323 if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700324 SLOGE("ASEC image file creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800325 return -1;
326 }
327
San Mehatd9a4e352010-03-12 13:32:47 -0800328 char idHash[33];
329 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700330 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800331 unlink(asecFileName);
332 return -1;
333 }
334
San Mehata19b2502010-01-06 10:33:53 -0800335 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800336 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700337 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800338 unlink(asecFileName);
339 return -1;
340 }
341
San Mehatb78a32c2010-01-10 13:02:12 -0800342 char dmDevice[255];
343 bool cleanupDm = false;
San Mehata19b2502010-01-06 10:33:53 -0800344
San Mehatb78a32c2010-01-10 13:02:12 -0800345 if (strcmp(key, "none")) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800346 // XXX: This is all we support for now
347 sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
San Mehatd9a4e352010-03-12 13:32:47 -0800348 if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
San Mehatb78a32c2010-01-10 13:02:12 -0800349 sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700350 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800351 Loop::destroyByDevice(loopDevice);
352 unlink(asecFileName);
353 return -1;
354 }
355 cleanupDm = true;
356 } else {
San Mehatfcf24fe2010-03-03 12:37:32 -0800357 sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
San Mehatb78a32c2010-01-10 13:02:12 -0800358 strcpy(dmDevice, loopDevice);
359 }
360
San Mehatfcf24fe2010-03-03 12:37:32 -0800361 /*
362 * Drop down the superblock at the end of the file
363 */
364
365 int sbfd = open(loopDevice, O_RDWR);
366 if (sbfd < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700367 SLOGE("Failed to open new DM device for superblock write (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800368 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800369 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800370 }
371 Loop::destroyByDevice(loopDevice);
372 unlink(asecFileName);
373 return -1;
374 }
375
376 if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
377 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700378 SLOGE("Failed to lseek for superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800379 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800380 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800381 }
382 Loop::destroyByDevice(loopDevice);
383 unlink(asecFileName);
384 return -1;
385 }
386
387 if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) {
388 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700389 SLOGE("Failed to write superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800390 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800391 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800392 }
393 Loop::destroyByDevice(loopDevice);
394 unlink(asecFileName);
395 return -1;
396 }
397 close(sbfd);
398
Kenny Root344ca102012-04-03 17:23:01 -0700399 if (wantFilesystem) {
400 int formatStatus;
rpcraiga54e13a2012-09-21 14:17:08 -0400401 char mountPoint[255];
402
rpcraigd1c226f2012-10-09 06:58:16 -0400403 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
404 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
405 SLOGE("ASEC fs format failed: couldn't construct mountPoint");
406 if (cleanupDm) {
407 Devmapper::destroy(idHash);
408 }
409 Loop::destroyByDevice(loopDevice);
410 unlink(asecFileName);
411 return -1;
412 }
rpcraiga54e13a2012-09-21 14:17:08 -0400413
Kenny Root344ca102012-04-03 17:23:01 -0700414 if (usingExt4) {
rpcraiga54e13a2012-09-21 14:17:08 -0400415 formatStatus = Ext4::format(dmDevice, mountPoint);
Kenny Root344ca102012-04-03 17:23:01 -0700416 } else {
417 formatStatus = Fat::format(dmDevice, numImgSectors);
San Mehatb78a32c2010-01-10 13:02:12 -0800418 }
San Mehata19b2502010-01-06 10:33:53 -0800419
Kenny Root344ca102012-04-03 17:23:01 -0700420 if (formatStatus < 0) {
421 SLOGE("ASEC fs format failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800422 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800423 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800424 }
San Mehateb13a902010-01-07 12:12:50 -0800425 Loop::destroyByDevice(loopDevice);
426 unlink(asecFileName);
427 return -1;
428 }
Kenny Root344ca102012-04-03 17:23:01 -0700429
Kenny Root344ca102012-04-03 17:23:01 -0700430 if (mkdir(mountPoint, 0000)) {
San Mehata1091cb2010-02-28 20:17:20 -0800431 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -0700432 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800433 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800434 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800435 }
436 Loop::destroyByDevice(loopDevice);
437 unlink(asecFileName);
438 return -1;
439 }
San Mehatb78a32c2010-01-10 13:02:12 -0800440 }
San Mehata1091cb2010-02-28 20:17:20 -0800441
Kenny Root344ca102012-04-03 17:23:01 -0700442 int mountStatus;
443 if (usingExt4) {
444 mountStatus = Ext4::doMount(dmDevice, mountPoint, false, false, false);
445 } else {
446 mountStatus = Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid, 0, 0000,
447 false);
448 }
449
450 if (mountStatus) {
San Mehat97ac40e2010-03-24 10:24:19 -0700451 SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800452 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800453 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800454 }
455 Loop::destroyByDevice(loopDevice);
456 unlink(asecFileName);
457 return -1;
458 }
Kenny Root344ca102012-04-03 17:23:01 -0700459
460 if (usingExt4) {
461 int dirfd = open(mountPoint, O_DIRECTORY);
462 if (dirfd >= 0) {
463 if (fchown(dirfd, ownerUid, AID_SYSTEM)
464 || fchmod(dirfd, S_IRUSR | S_IWUSR | S_IXUSR | S_ISGID | S_IRGRP | S_IXGRP)) {
465 SLOGI("Cannot chown/chmod new ASEC mount point %s", mountPoint);
466 }
467 close(dirfd);
468 }
469 }
San Mehata1091cb2010-02-28 20:17:20 -0800470 } else {
San Mehat97ac40e2010-03-24 10:24:19 -0700471 SLOGI("Created raw secure container %s (no filesystem)", id);
San Mehata19b2502010-01-06 10:33:53 -0800472 }
San Mehat88705162010-01-15 09:26:28 -0800473
Kenny Rootcbacf782010-09-24 15:11:48 -0700474 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehata19b2502010-01-06 10:33:53 -0800475 return 0;
476}
477
478int VolumeManager::finalizeAsec(const char *id) {
479 char asecFileName[255];
480 char loopDevice[255];
481 char mountPoint[255];
482
Kenny Root344ca102012-04-03 17:23:01 -0700483 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
484 SLOGE("Couldn't find ASEC %s", id);
485 return -1;
486 }
San Mehata19b2502010-01-06 10:33:53 -0800487
San Mehatd9a4e352010-03-12 13:32:47 -0800488 char idHash[33];
489 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700490 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800491 return -1;
492 }
493
494 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700495 SLOGE("Unable to finalize %s (%s)", id, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800496 return -1;
497 }
498
Kenny Root344ca102012-04-03 17:23:01 -0700499 unsigned int nr_sec = 0;
500 struct asec_superblock sb;
501
502 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
503 return -1;
504 }
505
rpcraigd1c226f2012-10-09 06:58:16 -0400506 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
507 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
508 SLOGE("ASEC finalize failed: couldn't construct mountPoint");
509 return -1;
510 }
Kenny Root344ca102012-04-03 17:23:01 -0700511
512 int result = 0;
513 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
514 result = Ext4::doMount(loopDevice, mountPoint, true, true, true);
515 } else {
516 result = Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false);
517 }
518
519 if (result) {
San Mehat97ac40e2010-03-24 10:24:19 -0700520 SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800521 return -1;
522 }
523
San Mehatd9a4e352010-03-12 13:32:47 -0800524 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700525 SLOGD("ASEC %s finalized", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800526 }
San Mehata19b2502010-01-06 10:33:53 -0800527 return 0;
528}
529
Kenny Root344ca102012-04-03 17:23:01 -0700530int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* filename) {
531 char asecFileName[255];
532 char loopDevice[255];
533 char mountPoint[255];
534
535 if (gid < AID_APP) {
536 SLOGE("Group ID is not in application range");
537 return -1;
538 }
539
540 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
541 SLOGE("Couldn't find ASEC %s", id);
542 return -1;
543 }
544
545 char idHash[33];
546 if (!asecHash(id, idHash, sizeof(idHash))) {
547 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
548 return -1;
549 }
550
551 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
552 SLOGE("Unable fix permissions during lookup on %s (%s)", id, strerror(errno));
553 return -1;
554 }
555
556 unsigned int nr_sec = 0;
557 struct asec_superblock sb;
558
559 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
560 return -1;
561 }
562
rpcraigd1c226f2012-10-09 06:58:16 -0400563 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
564 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
565 SLOGE("Unable remount to fix permissions for %s: couldn't construct mountpoint", id);
566 return -1;
567 }
Kenny Root344ca102012-04-03 17:23:01 -0700568
569 int result = 0;
570 if ((sb.c_opts & ASEC_SB_C_OPTS_EXT4) == 0) {
571 return 0;
572 }
573
574 int ret = Ext4::doMount(loopDevice, mountPoint,
575 false /* read-only */,
576 true /* remount */,
577 false /* executable */);
578 if (ret) {
579 SLOGE("Unable remount to fix permissions for %s (%s)", id, strerror(errno));
580 return -1;
581 }
582
583 char *paths[] = { mountPoint, NULL };
584
585 FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL);
586 if (fts) {
587 // Traverse the entire hierarchy and chown to system UID.
588 for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
589 // We don't care about the lost+found directory.
590 if (!strcmp(ftsent->fts_name, "lost+found")) {
591 continue;
592 }
593
594 /*
595 * There can only be one file marked as private right now.
596 * This should be more robust, but it satisfies the requirements
597 * we have for right now.
598 */
599 const bool privateFile = !strcmp(ftsent->fts_name, filename);
600
601 int fd = open(ftsent->fts_accpath, O_NOFOLLOW);
602 if (fd < 0) {
603 SLOGE("Couldn't open file %s: %s", ftsent->fts_accpath, strerror(errno));
604 result = -1;
605 continue;
606 }
607
608 result |= fchown(fd, AID_SYSTEM, privateFile? gid : AID_SYSTEM);
609
610 if (ftsent->fts_info & FTS_D) {
Kenny Root1a673c82012-05-10 16:45:29 -0700611 result |= fchmod(fd, 0755);
Kenny Root348c8ab2012-05-10 15:39:53 -0700612 } else if (ftsent->fts_info & FTS_F) {
Kenny Root344ca102012-04-03 17:23:01 -0700613 result |= fchmod(fd, privateFile ? 0640 : 0644);
614 }
615 close(fd);
616 }
617 fts_close(fts);
618
619 // Finally make the directory readable by everyone.
620 int dirfd = open(mountPoint, O_DIRECTORY);
621 if (dirfd < 0 || fchmod(dirfd, 0755)) {
622 SLOGE("Couldn't change owner of existing directory %s: %s", mountPoint, strerror(errno));
623 result |= -1;
624 }
625 close(dirfd);
626 } else {
627 result |= -1;
628 }
629
630 result |= Ext4::doMount(loopDevice, mountPoint,
631 true /* read-only */,
632 true /* remount */,
633 true /* execute */);
634
635 if (result) {
636 SLOGE("ASEC fix permissions failed (%s)", strerror(errno));
637 return -1;
638 }
639
640 if (mDebug) {
641 SLOGD("ASEC %s permissions fixed", id);
642 }
643 return 0;
644}
645
San Mehat048b0802010-01-23 08:17:06 -0800646int VolumeManager::renameAsec(const char *id1, const char *id2) {
Kenny Root344ca102012-04-03 17:23:01 -0700647 char asecFilename1[255];
San Mehat048b0802010-01-23 08:17:06 -0800648 char *asecFilename2;
649 char mountPoint[255];
650
Kenny Root344ca102012-04-03 17:23:01 -0700651 const char *dir;
652
653 if (findAsec(id1, asecFilename1, sizeof(asecFilename1), &dir)) {
654 SLOGE("Couldn't find ASEC %s", id1);
655 return -1;
656 }
657
658 asprintf(&asecFilename2, "%s/%s.asec", dir, id2);
San Mehat048b0802010-01-23 08:17:06 -0800659
rpcraigd1c226f2012-10-09 06:58:16 -0400660 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
661 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
662 SLOGE("Rename failed: couldn't construct mountpoint");
663 goto out_err;
664 }
665
San Mehat048b0802010-01-23 08:17:06 -0800666 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700667 SLOGW("Rename attempt when src mounted");
San Mehat048b0802010-01-23 08:17:06 -0800668 errno = EBUSY;
669 goto out_err;
670 }
671
rpcraigd1c226f2012-10-09 06:58:16 -0400672 written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2);
673 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
674 SLOGE("Rename failed: couldn't construct mountpoint2");
675 goto out_err;
676 }
677
San Mehat96956ed2010-02-24 08:42:51 -0800678 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700679 SLOGW("Rename attempt when dst mounted");
San Mehat96956ed2010-02-24 08:42:51 -0800680 errno = EBUSY;
681 goto out_err;
682 }
683
San Mehat048b0802010-01-23 08:17:06 -0800684 if (!access(asecFilename2, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700685 SLOGE("Rename attempt when dst exists");
San Mehat048b0802010-01-23 08:17:06 -0800686 errno = EADDRINUSE;
687 goto out_err;
688 }
689
690 if (rename(asecFilename1, asecFilename2)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700691 SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
San Mehat048b0802010-01-23 08:17:06 -0800692 goto out_err;
693 }
694
San Mehat048b0802010-01-23 08:17:06 -0800695 free(asecFilename2);
696 return 0;
697
698out_err:
San Mehat048b0802010-01-23 08:17:06 -0800699 free(asecFilename2);
700 return -1;
701}
702
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700703#define UNMOUNT_RETRIES 5
704#define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
San Mehat4ba89482010-02-18 09:00:18 -0800705int VolumeManager::unmountAsec(const char *id, bool force) {
San Mehata19b2502010-01-06 10:33:53 -0800706 char asecFileName[255];
707 char mountPoint[255];
708
Kenny Root344ca102012-04-03 17:23:01 -0700709 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
710 SLOGE("Couldn't find ASEC %s", id);
711 return -1;
712 }
713
rpcraigd1c226f2012-10-09 06:58:16 -0400714 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
715 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
716 SLOGE("ASEC unmount failed for %s: couldn't construct mountpoint", id);
717 return -1;
718 }
San Mehata19b2502010-01-06 10:33:53 -0800719
San Mehatd9a4e352010-03-12 13:32:47 -0800720 char idHash[33];
721 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700722 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800723 return -1;
724 }
725
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700726 return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
727}
728
Kenny Root508c0e12010-07-12 09:59:49 -0700729int VolumeManager::unmountObb(const char *fileName, bool force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700730 char mountPoint[255];
731
732 char idHash[33];
733 if (!asecHash(fileName, idHash, sizeof(idHash))) {
734 SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
735 return -1;
736 }
737
rpcraigd1c226f2012-10-09 06:58:16 -0400738 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
739 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
740 SLOGE("OBB unmount failed for %s: couldn't construct mountpoint", fileName);
741 return -1;
742 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700743
744 return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
745}
746
747int VolumeManager::unmountLoopImage(const char *id, const char *idHash,
748 const char *fileName, const char *mountPoint, bool force) {
San Mehat0586d542010-01-12 15:38:59 -0800749 if (!isMountpointMounted(mountPoint)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700750 SLOGE("Unmount request for %s when not mounted", id);
Kenny Root918e5f92010-09-30 18:00:52 -0700751 errno = ENOENT;
San Mehatb78a32c2010-01-10 13:02:12 -0800752 return -1;
753 }
San Mehat23969932010-01-09 07:08:06 -0800754
San Mehatb78a32c2010-01-10 13:02:12 -0800755 int i, rc;
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700756 for (i = 1; i <= UNMOUNT_RETRIES; i++) {
San Mehatb78a32c2010-01-10 13:02:12 -0800757 rc = umount(mountPoint);
758 if (!rc) {
759 break;
San Mehata19b2502010-01-06 10:33:53 -0800760 }
San Mehatb78a32c2010-01-10 13:02:12 -0800761 if (rc && (errno == EINVAL || errno == ENOENT)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700762 SLOGI("Container %s unmounted OK", id);
San Mehatb78a32c2010-01-10 13:02:12 -0800763 rc = 0;
764 break;
San Mehata19b2502010-01-06 10:33:53 -0800765 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700766 SLOGW("%s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -0800767 id, i, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800768
San Mehat4ba89482010-02-18 09:00:18 -0800769 int action = 0; // default is to just complain
770
771 if (force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700772 if (i > (UNMOUNT_RETRIES - 2))
San Mehat4ba89482010-02-18 09:00:18 -0800773 action = 2; // SIGKILL
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700774 else if (i > (UNMOUNT_RETRIES - 3))
San Mehat4ba89482010-02-18 09:00:18 -0800775 action = 1; // SIGHUP
776 }
San Mehat8c940ef2010-02-13 14:19:53 -0800777
San Mehat586536c2010-02-16 17:12:00 -0800778 Process::killProcessesWithOpenFiles(mountPoint, action);
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700779 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehatb78a32c2010-01-10 13:02:12 -0800780 }
781
782 if (rc) {
San Mehat4ba89482010-02-18 09:00:18 -0800783 errno = EBUSY;
San Mehat97ac40e2010-03-24 10:24:19 -0700784 SLOGE("Failed to unmount container %s (%s)", id, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800785 return -1;
786 }
787
San Mehat12f4b892010-02-24 11:43:22 -0800788 int retries = 10;
789
790 while(retries--) {
791 if (!rmdir(mountPoint)) {
792 break;
793 }
794
San Mehat97ac40e2010-03-24 10:24:19 -0700795 SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700796 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehat12f4b892010-02-24 11:43:22 -0800797 }
798
799 if (!retries) {
San Mehat97ac40e2010-03-24 10:24:19 -0700800 SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
San Mehatf5c61982010-02-03 11:04:46 -0800801 }
San Mehat88705162010-01-15 09:26:28 -0800802
San Mehatd9a4e352010-03-12 13:32:47 -0800803 if (Devmapper::destroy(idHash) && errno != ENXIO) {
San Mehat97ac40e2010-03-24 10:24:19 -0700804 SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800805 }
806
807 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800808 if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800809 Loop::destroyByDevice(loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800810 } else {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700811 SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800812 }
San Mehat88705162010-01-15 09:26:28 -0800813
814 AsecIdCollection::iterator it;
815 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
Kenny Rootcbacf782010-09-24 15:11:48 -0700816 ContainerData* cd = *it;
817 if (!strcmp(cd->id, id)) {
San Mehat88705162010-01-15 09:26:28 -0800818 free(*it);
819 mActiveContainers->erase(it);
820 break;
821 }
822 }
823 if (it == mActiveContainers->end()) {
San Mehat97ac40e2010-03-24 10:24:19 -0700824 SLOGW("mActiveContainers is inconsistent!");
San Mehat88705162010-01-15 09:26:28 -0800825 }
San Mehatb78a32c2010-01-10 13:02:12 -0800826 return 0;
827}
828
San Mehat4ba89482010-02-18 09:00:18 -0800829int VolumeManager::destroyAsec(const char *id, bool force) {
San Mehatb78a32c2010-01-10 13:02:12 -0800830 char asecFileName[255];
831 char mountPoint[255];
832
Kenny Root344ca102012-04-03 17:23:01 -0700833 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
834 SLOGE("Couldn't find ASEC %s", id);
835 return -1;
836 }
837
rpcraigd1c226f2012-10-09 06:58:16 -0400838 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
839 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
840 SLOGE("ASEC destroy failed for %s: couldn't construct mountpoint", id);
841 return -1;
842 }
San Mehatb78a32c2010-01-10 13:02:12 -0800843
San Mehat0586d542010-01-12 15:38:59 -0800844 if (isMountpointMounted(mountPoint)) {
San Mehatd9a4e352010-03-12 13:32:47 -0800845 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700846 SLOGD("Unmounting container before destroy");
San Mehatd9a4e352010-03-12 13:32:47 -0800847 }
San Mehat4ba89482010-02-18 09:00:18 -0800848 if (unmountAsec(id, force)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700849 SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800850 return -1;
851 }
852 }
San Mehata19b2502010-01-06 10:33:53 -0800853
San Mehat0586d542010-01-12 15:38:59 -0800854 if (unlink(asecFileName)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700855 SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800856 return -1;
857 }
San Mehata19b2502010-01-06 10:33:53 -0800858
San Mehatd9a4e352010-03-12 13:32:47 -0800859 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700860 SLOGD("ASEC %s destroyed", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800861 }
San Mehata19b2502010-01-06 10:33:53 -0800862 return 0;
863}
864
Kenny Root344ca102012-04-03 17:23:01 -0700865bool VolumeManager::isAsecInDirectory(const char *dir, const char *asecName) const {
866 int dirfd = open(dir, O_DIRECTORY);
867 if (dirfd < 0) {
868 SLOGE("Couldn't open internal ASEC dir (%s)", strerror(errno));
869 return -1;
870 }
871
872 bool ret = false;
873
874 if (!faccessat(dirfd, asecName, F_OK, AT_SYMLINK_NOFOLLOW)) {
875 ret = true;
876 }
877
878 close(dirfd);
879
880 return ret;
881}
882
883int VolumeManager::findAsec(const char *id, char *asecPath, size_t asecPathLen,
884 const char **directory) const {
885 int dirfd, fd;
886 const int idLen = strlen(id);
887 char *asecName;
888
889 if (asprintf(&asecName, "%s.asec", id) < 0) {
890 SLOGE("Couldn't allocate string to write ASEC name");
891 return -1;
892 }
893
894 const char *dir;
895 if (isAsecInDirectory(Volume::SEC_ASECDIR_INT, asecName)) {
896 dir = Volume::SEC_ASECDIR_INT;
897 } else if (isAsecInDirectory(Volume::SEC_ASECDIR_EXT, asecName)) {
898 dir = Volume::SEC_ASECDIR_EXT;
899 } else {
900 free(asecName);
901 return -1;
902 }
903
904 if (directory != NULL) {
905 *directory = dir;
906 }
907
908 if (asecPath != NULL) {
909 int written = snprintf(asecPath, asecPathLen, "%s/%s", dir, asecName);
rpcraigd1c226f2012-10-09 06:58:16 -0400910 if ((written < 0) || (size_t(written) >= asecPathLen)) {
911 SLOGE("findAsec failed for %s: couldn't construct ASEC path", id);
Kenny Root344ca102012-04-03 17:23:01 -0700912 free(asecName);
913 return -1;
914 }
915 }
916
917 free(asecName);
918 return 0;
919}
920
San Mehata19b2502010-01-06 10:33:53 -0800921int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
922 char asecFileName[255];
923 char mountPoint[255];
924
Kenny Root344ca102012-04-03 17:23:01 -0700925 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
926 SLOGE("Couldn't find ASEC %s", id);
927 return -1;
928 }
929
rpcraigd1c226f2012-10-09 06:58:16 -0400930 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
931 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
932 SLOGE("ASEC mount failed: couldn't construct mountpoint", id);
933 return -1;
934 }
San Mehata19b2502010-01-06 10:33:53 -0800935
936 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700937 SLOGE("ASEC %s already mounted", id);
San Mehata19b2502010-01-06 10:33:53 -0800938 errno = EBUSY;
939 return -1;
940 }
941
San Mehatd9a4e352010-03-12 13:32:47 -0800942 char idHash[33];
943 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700944 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800945 return -1;
946 }
Kenny Root7b18a7b2010-03-15 13:13:41 -0700947
San Mehata19b2502010-01-06 10:33:53 -0800948 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800949 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
950 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700951 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800952 return -1;
953 }
San Mehatd9a4e352010-03-12 13:32:47 -0800954 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700955 SLOGD("New loop device created at %s", loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800956 }
San Mehatb78a32c2010-01-10 13:02:12 -0800957 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800958 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700959 SLOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800960 }
San Mehatb78a32c2010-01-10 13:02:12 -0800961 }
962
963 char dmDevice[255];
964 bool cleanupDm = false;
San Mehatfcf24fe2010-03-03 12:37:32 -0800965 int fd;
966 unsigned int nr_sec = 0;
San Mehatfcf24fe2010-03-03 12:37:32 -0800967 struct asec_superblock sb;
San Mehatfcf24fe2010-03-03 12:37:32 -0800968
Kenny Root344ca102012-04-03 17:23:01 -0700969 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
970 return -1;
971 }
San Mehatfcf24fe2010-03-03 12:37:32 -0800972
San Mehatd9a4e352010-03-12 13:32:47 -0800973 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700974 SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatd9a4e352010-03-12 13:32:47 -0800975 }
San Mehatfcf24fe2010-03-03 12:37:32 -0800976 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
San Mehat97ac40e2010-03-24 10:24:19 -0700977 SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatfcf24fe2010-03-03 12:37:32 -0800978 Loop::destroyByDevice(loopDevice);
979 errno = EMEDIUMTYPE;
980 return -1;
981 }
982 nr_sec--; // We don't want the devmapping to extend onto our superblock
983
San Mehatb78a32c2010-01-10 13:02:12 -0800984 if (strcmp(key, "none")) {
San Mehatd9a4e352010-03-12 13:32:47 -0800985 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
986 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
San Mehatb78a32c2010-01-10 13:02:12 -0800987 dmDevice, sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700988 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800989 Loop::destroyByDevice(loopDevice);
990 return -1;
991 }
San Mehatd9a4e352010-03-12 13:32:47 -0800992 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700993 SLOGD("New devmapper instance created at %s", dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800994 }
San Mehatb78a32c2010-01-10 13:02:12 -0800995 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800996 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700997 SLOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800998 }
San Mehatb78a32c2010-01-10 13:02:12 -0800999 }
1000 cleanupDm = true;
1001 } else {
1002 strcpy(dmDevice, loopDevice);
San Mehata19b2502010-01-06 10:33:53 -08001003 }
1004
Kenny Root344ca102012-04-03 17:23:01 -07001005 if (mkdir(mountPoint, 0000)) {
San Mehatb78a32c2010-01-10 13:02:12 -08001006 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -07001007 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001008 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -08001009 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -08001010 }
1011 Loop::destroyByDevice(loopDevice);
1012 return -1;
1013 }
San Mehata19b2502010-01-06 10:33:53 -08001014 }
1015
Kenny Rootcdc2a1c2012-05-03 13:49:46 -07001016 /*
1017 * The device mapper node needs to be created. Sometimes it takes a
1018 * while. Wait for up to 1 second. We could also inspect incoming uevents,
1019 * but that would take more effort.
1020 */
1021 int tries = 25;
1022 while (tries--) {
1023 if (!access(dmDevice, F_OK) || errno != ENOENT) {
1024 break;
1025 }
1026 usleep(40 * 1000);
1027 }
1028
Kenny Root344ca102012-04-03 17:23:01 -07001029 int result;
1030 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
1031 result = Ext4::doMount(dmDevice, mountPoint, true, false, true);
1032 } else {
1033 result = Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0, 0222, false);
1034 }
1035
1036 if (result) {
San Mehat97ac40e2010-03-24 10:24:19 -07001037 SLOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001038 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -08001039 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -08001040 }
1041 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -08001042 return -1;
1043 }
1044
Kenny Rootcbacf782010-09-24 15:11:48 -07001045 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehatd9a4e352010-03-12 13:32:47 -08001046 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001047 SLOGD("ASEC %s mounted", id);
San Mehatd9a4e352010-03-12 13:32:47 -08001048 }
San Mehata19b2502010-01-06 10:33:53 -08001049 return 0;
1050}
1051
Kenny Rooteacf7e02012-08-09 11:28:37 -07001052Volume* VolumeManager::getVolumeForFile(const char *fileName) {
1053 VolumeCollection::iterator i;
1054
1055 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1056 const char* mountPoint = (*i)->getMountpoint();
1057 if (!strncmp(fileName, mountPoint, strlen(mountPoint))) {
1058 return *i;
1059 }
1060 }
1061
1062 return NULL;
1063}
1064
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001065/**
1066 * Mounts an image file <code>img</code>.
1067 */
Kenny Root508c0e12010-07-12 09:59:49 -07001068int VolumeManager::mountObb(const char *img, const char *key, int ownerUid) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001069 char mountPoint[255];
1070
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001071 char idHash[33];
1072 if (!asecHash(img, idHash, sizeof(idHash))) {
1073 SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
1074 return -1;
1075 }
1076
rpcraigd1c226f2012-10-09 06:58:16 -04001077 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
1078 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1079 SLOGE("OBB mount failed: couldn't construct mountpoint", img);
1080 return -1;
1081 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001082
1083 if (isMountpointMounted(mountPoint)) {
1084 SLOGE("Image %s already mounted", img);
1085 errno = EBUSY;
1086 return -1;
1087 }
1088
1089 char loopDevice[255];
1090 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
1091 if (Loop::create(idHash, img, loopDevice, sizeof(loopDevice))) {
1092 SLOGE("Image loop device creation failed (%s)", strerror(errno));
1093 return -1;
1094 }
1095 if (mDebug) {
1096 SLOGD("New loop device created at %s", loopDevice);
1097 }
1098 } else {
1099 if (mDebug) {
1100 SLOGD("Found active loopback for %s at %s", img, loopDevice);
1101 }
1102 }
1103
1104 char dmDevice[255];
1105 bool cleanupDm = false;
1106 int fd;
1107 unsigned int nr_sec = 0;
1108
1109 if ((fd = open(loopDevice, O_RDWR)) < 0) {
1110 SLOGE("Failed to open loopdevice (%s)", strerror(errno));
1111 Loop::destroyByDevice(loopDevice);
1112 return -1;
1113 }
1114
1115 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
1116 SLOGE("Failed to get loop size (%s)", strerror(errno));
1117 Loop::destroyByDevice(loopDevice);
1118 close(fd);
1119 return -1;
1120 }
1121
1122 close(fd);
1123
1124 if (strcmp(key, "none")) {
1125 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
1126 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
1127 dmDevice, sizeof(dmDevice))) {
1128 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
1129 Loop::destroyByDevice(loopDevice);
1130 return -1;
1131 }
1132 if (mDebug) {
1133 SLOGD("New devmapper instance created at %s", dmDevice);
1134 }
1135 } else {
1136 if (mDebug) {
1137 SLOGD("Found active devmapper for %s at %s", img, dmDevice);
1138 }
1139 }
1140 cleanupDm = true;
1141 } else {
1142 strcpy(dmDevice, loopDevice);
1143 }
1144
1145 if (mkdir(mountPoint, 0755)) {
1146 if (errno != EEXIST) {
1147 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
1148 if (cleanupDm) {
1149 Devmapper::destroy(idHash);
1150 }
1151 Loop::destroyByDevice(loopDevice);
1152 return -1;
1153 }
1154 }
1155
Kenny Roota3e06082010-08-27 08:31:35 -07001156 if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0,
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001157 0227, false)) {
1158 SLOGE("Image mount failed (%s)", strerror(errno));
1159 if (cleanupDm) {
1160 Devmapper::destroy(idHash);
1161 }
1162 Loop::destroyByDevice(loopDevice);
1163 return -1;
1164 }
1165
Kenny Rootcbacf782010-09-24 15:11:48 -07001166 mActiveContainers->push_back(new ContainerData(strdup(img), OBB));
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001167 if (mDebug) {
1168 SLOGD("Image %s mounted", img);
1169 }
1170 return 0;
1171}
1172
San Mehat49e2bce2009-10-12 16:29:01 -07001173int VolumeManager::mountVolume(const char *label) {
1174 Volume *v = lookupVolume(label);
1175
1176 if (!v) {
1177 errno = ENOENT;
1178 return -1;
1179 }
1180
San Mehata2677e42009-12-13 10:40:18 -08001181 return v->mountVol();
1182}
1183
Kenny Root508c0e12010-07-12 09:59:49 -07001184int VolumeManager::listMountedObbs(SocketClient* cli) {
1185 char device[256];
1186 char mount_path[256];
1187 char rest[256];
1188 FILE *fp;
1189 char line[1024];
1190
1191 if (!(fp = fopen("/proc/mounts", "r"))) {
1192 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
1193 return -1;
1194 }
1195
1196 // Create a string to compare against that has a trailing slash
Kenny Rooteacf7e02012-08-09 11:28:37 -07001197 int loopDirLen = strlen(Volume::LOOPDIR);
Kenny Root508c0e12010-07-12 09:59:49 -07001198 char loopDir[loopDirLen + 2];
1199 strcpy(loopDir, Volume::LOOPDIR);
1200 loopDir[loopDirLen++] = '/';
1201 loopDir[loopDirLen] = '\0';
1202
1203 while(fgets(line, sizeof(line), fp)) {
1204 line[strlen(line)-1] = '\0';
1205
1206 /*
1207 * Should look like:
1208 * /dev/block/loop0 /mnt/obb/fc99df1323fd36424f864dcb76b76d65 ...
1209 */
1210 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1211
1212 if (!strncmp(mount_path, loopDir, loopDirLen)) {
1213 int fd = open(device, O_RDONLY);
1214 if (fd >= 0) {
1215 struct loop_info64 li;
1216 if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
1217 cli->sendMsg(ResponseCode::AsecListResult,
1218 (const char*) li.lo_file_name, false);
1219 }
1220 close(fd);
1221 }
1222 }
1223 }
1224
1225 fclose(fp);
1226 return 0;
1227}
1228
San Mehateba65e92010-01-29 05:15:16 -08001229int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
1230 Volume *v = lookupVolume(label);
1231
1232 if (!v) {
1233 errno = ENOENT;
1234 return -1;
1235 }
1236
1237 if (strcmp(method, "ums")) {
1238 errno = ENOSYS;
1239 return -1;
1240 }
1241
1242 if (v->getState() != Volume::State_Shared) {
San Mehateba65e92010-01-29 05:15:16 -08001243 *enabled = false;
San Mehatb9aed742010-02-04 15:07:01 -08001244 } else {
1245 *enabled = true;
San Mehateba65e92010-01-29 05:15:16 -08001246 }
1247 return 0;
1248}
1249
San Mehata2677e42009-12-13 10:40:18 -08001250int VolumeManager::shareVolume(const char *label, const char *method) {
1251 Volume *v = lookupVolume(label);
1252
1253 if (!v) {
1254 errno = ENOENT;
1255 return -1;
1256 }
1257
1258 /*
1259 * Eventually, we'll want to support additional share back-ends,
1260 * some of which may work while the media is mounted. For now,
1261 * we just support UMS
1262 */
1263 if (strcmp(method, "ums")) {
1264 errno = ENOSYS;
1265 return -1;
1266 }
1267
1268 if (v->getState() == Volume::State_NoMedia) {
1269 errno = ENODEV;
1270 return -1;
1271 }
1272
San Mehat49e2bce2009-10-12 16:29:01 -07001273 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -08001274 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -07001275 errno = EBUSY;
1276 return -1;
1277 }
1278
Ken Sumrall3b170052011-07-11 15:38:57 -07001279 if (mVolManagerDisabled) {
1280 errno = EBUSY;
1281 return -1;
1282 }
1283
Mike Lockwood2dfe2972010-09-17 18:50:51 -04001284 dev_t d = v->getShareDevice();
San Mehata2677e42009-12-13 10:40:18 -08001285 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
1286 // This volume does not support raw disk access
1287 errno = EINVAL;
1288 return -1;
1289 }
1290
1291 int fd;
1292 char nodepath[255];
rpcraigd1c226f2012-10-09 06:58:16 -04001293 int written = snprintf(nodepath,
San Mehata2677e42009-12-13 10:40:18 -08001294 sizeof(nodepath), "/dev/block/vold/%d:%d",
1295 MAJOR(d), MINOR(d));
1296
rpcraigd1c226f2012-10-09 06:58:16 -04001297 if ((written < 0) || (size_t(written) >= sizeof(nodepath))) {
1298 SLOGE("shareVolume failed: couldn't construct nodepath");
1299 return -1;
1300 }
1301
Mike Lockwood97f2fc12011-06-07 10:51:38 -07001302 if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001303 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001304 return -1;
1305 }
1306
1307 if (write(fd, nodepath, strlen(nodepath)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001308 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001309 close(fd);
1310 return -1;
1311 }
1312
1313 close(fd);
1314 v->handleVolumeShared();
Mike Lockwooda28056b2010-10-28 15:21:24 -04001315 if (mUmsSharingCount++ == 0) {
1316 FILE* fp;
1317 mSavedDirtyRatio = -1; // in case we fail
1318 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1319 char line[16];
1320 if (fgets(line, sizeof(line), fp) && sscanf(line, "%d", &mSavedDirtyRatio)) {
1321 fprintf(fp, "%d\n", mUmsDirtyRatio);
1322 } else {
1323 SLOGE("Failed to read dirty_ratio (%s)", strerror(errno));
1324 }
1325 fclose(fp);
1326 } else {
1327 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1328 }
1329 }
San Mehata2677e42009-12-13 10:40:18 -08001330 return 0;
1331}
1332
1333int VolumeManager::unshareVolume(const char *label, const char *method) {
1334 Volume *v = lookupVolume(label);
1335
1336 if (!v) {
1337 errno = ENOENT;
1338 return -1;
1339 }
1340
1341 if (strcmp(method, "ums")) {
1342 errno = ENOSYS;
1343 return -1;
1344 }
1345
1346 if (v->getState() != Volume::State_Shared) {
1347 errno = EINVAL;
1348 return -1;
1349 }
1350
San Mehata2677e42009-12-13 10:40:18 -08001351 int fd;
Mike Lockwood97f2fc12011-06-07 10:51:38 -07001352 if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001353 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001354 return -1;
1355 }
1356
1357 char ch = 0;
1358 if (write(fd, &ch, 1) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001359 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001360 close(fd);
1361 return -1;
1362 }
1363
1364 close(fd);
1365 v->handleVolumeUnshared();
Mike Lockwooda28056b2010-10-28 15:21:24 -04001366 if (--mUmsSharingCount == 0 && mSavedDirtyRatio != -1) {
1367 FILE* fp;
1368 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1369 fprintf(fp, "%d\n", mSavedDirtyRatio);
1370 fclose(fp);
1371 } else {
1372 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1373 }
1374 mSavedDirtyRatio = -1;
1375 }
San Mehata2677e42009-12-13 10:40:18 -08001376 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -07001377}
1378
Ken Sumrall3b170052011-07-11 15:38:57 -07001379extern "C" int vold_disableVol(const char *label) {
Ken Sumrall29d8da82011-05-18 17:20:07 -07001380 VolumeManager *vm = VolumeManager::Instance();
Ken Sumrall3b170052011-07-11 15:38:57 -07001381 vm->disableVolumeManager();
1382 vm->unshareVolume(label, "ums");
Ken Sumrall0b8b5972011-08-31 16:14:23 -07001383 return vm->unmountVolume(label, true, false);
Ken Sumrall29d8da82011-05-18 17:20:07 -07001384}
1385
1386extern "C" int vold_getNumDirectVolumes(void) {
1387 VolumeManager *vm = VolumeManager::Instance();
1388 return vm->getNumDirectVolumes();
1389}
1390
1391int VolumeManager::getNumDirectVolumes(void) {
1392 VolumeCollection::iterator i;
1393 int n=0;
1394
1395 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1396 if ((*i)->getShareDevice() != (dev_t)0) {
1397 n++;
1398 }
1399 }
1400 return n;
1401}
1402
1403extern "C" int vold_getDirectVolumeList(struct volume_info *vol_list) {
1404 VolumeManager *vm = VolumeManager::Instance();
1405 return vm->getDirectVolumeList(vol_list);
1406}
1407
1408int VolumeManager::getDirectVolumeList(struct volume_info *vol_list) {
1409 VolumeCollection::iterator i;
1410 int n=0;
1411 dev_t d;
1412
1413 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1414 if ((d=(*i)->getShareDevice()) != (dev_t)0) {
1415 (*i)->getVolInfo(&vol_list[n]);
1416 snprintf(vol_list[n].blk_dev, sizeof(vol_list[n].blk_dev),
1417 "/dev/block/vold/%d:%d",MAJOR(d), MINOR(d));
1418 n++;
1419 }
1420 }
1421
1422 return 0;
1423}
1424
Ken Sumrall0b8b5972011-08-31 16:14:23 -07001425int VolumeManager::unmountVolume(const char *label, bool force, bool revert) {
San Mehat49e2bce2009-10-12 16:29:01 -07001426 Volume *v = lookupVolume(label);
1427
1428 if (!v) {
1429 errno = ENOENT;
1430 return -1;
1431 }
1432
San Mehata2677e42009-12-13 10:40:18 -08001433 if (v->getState() == Volume::State_NoMedia) {
1434 errno = ENODEV;
1435 return -1;
1436 }
1437
San Mehat49e2bce2009-10-12 16:29:01 -07001438 if (v->getState() != Volume::State_Mounted) {
San Mehat97ac40e2010-03-24 10:24:19 -07001439 SLOGW("Attempt to unmount volume which isn't mounted (%d)\n",
San Mehata2677e42009-12-13 10:40:18 -08001440 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -07001441 errno = EBUSY;
Ken Sumrall319b1042011-06-14 14:01:55 -07001442 return UNMOUNT_NOT_MOUNTED_ERR;
San Mehat49e2bce2009-10-12 16:29:01 -07001443 }
1444
San Mehat1a06eda2010-04-15 12:58:50 -07001445 cleanupAsec(v, force);
San Mehat88705162010-01-15 09:26:28 -08001446
Ken Sumrall0b8b5972011-08-31 16:14:23 -07001447 return v->unmountVol(force, revert);
San Mehat49e2bce2009-10-12 16:29:01 -07001448}
1449
Ken Sumrall425524d2012-06-14 20:55:28 -07001450extern "C" int vold_unmountAllAsecs(void) {
1451 int rc;
1452
1453 VolumeManager *vm = VolumeManager::Instance();
1454 rc = vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_EXT);
1455 if (vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_INT)) {
1456 rc = -1;
1457 }
1458 return rc;
1459}
1460
1461#define ID_BUF_LEN 256
1462#define ASEC_SUFFIX ".asec"
1463#define ASEC_SUFFIX_LEN (sizeof(ASEC_SUFFIX) - 1)
1464int VolumeManager::unmountAllAsecsInDir(const char *directory) {
1465 DIR *d = opendir(directory);
1466 int rc = 0;
1467
1468 if (!d) {
1469 SLOGE("Could not open asec dir %s", directory);
1470 return -1;
1471 }
1472
1473 size_t dirent_len = offsetof(struct dirent, d_name) +
Elliott Hughes8c480f72012-10-26 16:57:19 -07001474 fpathconf(dirfd(d), _PC_NAME_MAX) + 1;
Ken Sumrall425524d2012-06-14 20:55:28 -07001475
1476 struct dirent *dent = (struct dirent *) malloc(dirent_len);
1477 if (dent == NULL) {
1478 SLOGE("Failed to allocate memory for asec dir");
1479 return -1;
1480 }
1481
1482 struct dirent *result;
1483 while (!readdir_r(d, dent, &result) && result != NULL) {
1484 if (dent->d_name[0] == '.')
1485 continue;
1486 if (dent->d_type != DT_REG)
1487 continue;
1488 size_t name_len = strlen(dent->d_name);
1489 if (name_len > 5 && name_len < (ID_BUF_LEN + ASEC_SUFFIX_LEN - 1) &&
1490 !strcmp(&dent->d_name[name_len - 5], ASEC_SUFFIX)) {
1491 char id[ID_BUF_LEN];
1492 strlcpy(id, dent->d_name, name_len - 4);
1493 if (unmountAsec(id, true)) {
1494 /* Register the error, but try to unmount more asecs */
1495 rc = -1;
1496 }
1497 }
1498 }
1499 closedir(d);
1500
1501 free(dent);
1502
1503 return rc;
1504}
1505
San Mehata2677e42009-12-13 10:40:18 -08001506/*
1507 * Looks up a volume by it's label or mount-point
1508 */
San Mehat49e2bce2009-10-12 16:29:01 -07001509Volume *VolumeManager::lookupVolume(const char *label) {
1510 VolumeCollection::iterator i;
1511
1512 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -08001513 if (label[0] == '/') {
1514 if (!strcmp(label, (*i)->getMountpoint()))
1515 return (*i);
1516 } else {
1517 if (!strcmp(label, (*i)->getLabel()))
1518 return (*i);
1519 }
San Mehat49e2bce2009-10-12 16:29:01 -07001520 }
1521 return NULL;
1522}
San Mehata19b2502010-01-06 10:33:53 -08001523
1524bool VolumeManager::isMountpointMounted(const char *mp)
1525{
1526 char device[256];
1527 char mount_path[256];
1528 char rest[256];
1529 FILE *fp;
1530 char line[1024];
1531
1532 if (!(fp = fopen("/proc/mounts", "r"))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001533 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001534 return false;
1535 }
1536
1537 while(fgets(line, sizeof(line), fp)) {
1538 line[strlen(line)-1] = '\0';
1539 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1540 if (!strcmp(mount_path, mp)) {
1541 fclose(fp);
1542 return true;
1543 }
San Mehata19b2502010-01-06 10:33:53 -08001544 }
1545
1546 fclose(fp);
1547 return false;
1548}
1549
San Mehat1a06eda2010-04-15 12:58:50 -07001550int VolumeManager::cleanupAsec(Volume *v, bool force) {
Kenny Rooteacf7e02012-08-09 11:28:37 -07001551 int rc = unmountAllAsecsInDir(Volume::SEC_ASECDIR_EXT);
1552
1553 AsecIdCollection toUnmount;
1554 // Find the remaining OBB files that are on external storage.
1555 for (AsecIdCollection::iterator it = mActiveContainers->begin(); it != mActiveContainers->end();
1556 ++it) {
Kenny Rootcbacf782010-09-24 15:11:48 -07001557 ContainerData* cd = *it;
Kenny Rooteacf7e02012-08-09 11:28:37 -07001558
Kenny Rootcbacf782010-09-24 15:11:48 -07001559 if (cd->type == ASEC) {
Kenny Rooteacf7e02012-08-09 11:28:37 -07001560 // nothing
Kenny Rootcbacf782010-09-24 15:11:48 -07001561 } else if (cd->type == OBB) {
Kenny Rooteacf7e02012-08-09 11:28:37 -07001562 if (v == getVolumeForFile(cd->id)) {
1563 toUnmount.push_back(cd);
Kenny Rootcbacf782010-09-24 15:11:48 -07001564 }
1565 } else {
1566 SLOGE("Unknown container type %d!", cd->type);
San Mehat1a06eda2010-04-15 12:58:50 -07001567 }
1568 }
Kenny Rooteacf7e02012-08-09 11:28:37 -07001569
1570 for (AsecIdCollection::iterator it = toUnmount.begin(); it != toUnmount.end(); ++it) {
1571 ContainerData *cd = *it;
1572 SLOGI("Unmounting ASEC %s (dependant on %s)", cd->id, v->getMountpoint());
1573 if (unmountObb(cd->id, force)) {
1574 SLOGE("Failed to unmount OBB %s (%s)", cd->id, strerror(errno));
1575 rc = -1;
1576 }
1577 }
1578
1579 return rc;
1580
San Mehat1a06eda2010-04-15 12:58:50 -07001581}
1582