blob: ac1e1b9565b3598967a52e19c03495251fbb6a02 [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);
194 snprintf(mountPath, mountPathLen, "%s/%s", Volume::LOOPDIR, idHash);
195
196 if (access(mountPath, F_OK)) {
197 errno = ENOENT;
198 return -1;
199 }
200
201 return 0;
202}
203
San Mehata19b2502010-01-06 10:33:53 -0800204int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
San Mehat88ac2c02010-03-23 11:15:58 -0700205 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700206
Nick Kralevich0de7c612014-01-27 14:58:06 -0800207 if (!isLegalAsecId(id)) {
208 SLOGE("getAsecMountPath: Invalid asec id \"%s\"", id);
209 errno = EINVAL;
210 return -1;
211 }
212
Kenny Root344ca102012-04-03 17:23:01 -0700213 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
214 SLOGE("Couldn't find ASEC %s", id);
215 return -1;
216 }
San Mehat88ac2c02010-03-23 11:15:58 -0700217
218 memset(buffer, 0, maxlen);
219 if (access(asecFileName, F_OK)) {
220 errno = ENOENT;
221 return -1;
222 }
San Mehata19b2502010-01-06 10:33:53 -0800223
San Mehat3bb60202010-02-19 18:14:36 -0800224 snprintf(buffer, maxlen, "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800225 return 0;
226}
227
Dianne Hackborn736910c2011-06-27 13:37:07 -0700228int VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxlen) {
229 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700230
Nick Kralevich0de7c612014-01-27 14:58:06 -0800231 if (!isLegalAsecId(id)) {
232 SLOGE("getAsecFilesystemPath: Invalid asec id \"%s\"", id);
233 errno = EINVAL;
234 return -1;
235 }
236
Kenny Root344ca102012-04-03 17:23:01 -0700237 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
238 SLOGE("Couldn't find ASEC %s", id);
239 return -1;
240 }
Dianne Hackborn736910c2011-06-27 13:37:07 -0700241
242 memset(buffer, 0, maxlen);
243 if (access(asecFileName, F_OK)) {
244 errno = ENOENT;
245 return -1;
246 }
247
248 snprintf(buffer, maxlen, "%s", asecFileName);
249 return 0;
250}
251
Kenny Root344ca102012-04-03 17:23:01 -0700252int VolumeManager::createAsec(const char *id, unsigned int numSectors, const char *fstype,
253 const char *key, const int ownerUid, bool isExternal) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800254 struct asec_superblock sb;
255 memset(&sb, 0, sizeof(sb));
256
Nick Kralevich0de7c612014-01-27 14:58:06 -0800257 if (!isLegalAsecId(id)) {
258 SLOGE("createAsec: Invalid asec id \"%s\"", id);
259 errno = EINVAL;
260 return -1;
261 }
262
Kenny Root344ca102012-04-03 17:23:01 -0700263 const bool wantFilesystem = strcmp(fstype, "none");
264 bool usingExt4 = false;
265 if (wantFilesystem) {
266 usingExt4 = !strcmp(fstype, "ext4");
267 if (usingExt4) {
268 sb.c_opts |= ASEC_SB_C_OPTS_EXT4;
269 } else if (strcmp(fstype, "fat")) {
270 SLOGE("Invalid filesystem type %s", fstype);
271 errno = EINVAL;
272 return -1;
273 }
274 }
275
San Mehatfcf24fe2010-03-03 12:37:32 -0800276 sb.magic = ASEC_SB_MAGIC;
277 sb.ver = ASEC_SB_VER;
San Mehata19b2502010-01-06 10:33:53 -0800278
San Mehatd31e3802010-02-18 08:37:45 -0800279 if (numSectors < ((1024*1024)/512)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700280 SLOGE("Invalid container size specified (%d sectors)", numSectors);
San Mehatd31e3802010-02-18 08:37:45 -0800281 errno = EINVAL;
282 return -1;
283 }
284
San Mehata19b2502010-01-06 10:33:53 -0800285 if (lookupVolume(id)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700286 SLOGE("ASEC id '%s' currently exists", id);
San Mehata19b2502010-01-06 10:33:53 -0800287 errno = EADDRINUSE;
288 return -1;
289 }
290
291 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700292
293 if (!findAsec(id, asecFileName, sizeof(asecFileName))) {
294 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
295 asecFileName, strerror(errno));
296 errno = EADDRINUSE;
297 return -1;
298 }
299
300 const char *asecDir = isExternal ? Volume::SEC_ASECDIR_EXT : Volume::SEC_ASECDIR_INT;
301
302 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", asecDir, id);
San Mehata19b2502010-01-06 10:33:53 -0800303
304 if (!access(asecFileName, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700305 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
Kenny Root344ca102012-04-03 17:23:01 -0700306 asecFileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800307 errno = EADDRINUSE;
308 return -1;
309 }
310
San Mehatfcf24fe2010-03-03 12:37:32 -0800311 /*
312 * Add some headroom
313 */
314 unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
315 unsigned numImgSectors = numSectors + fatSize + 2;
316
317 if (numImgSectors % 63) {
318 numImgSectors += (63 - (numImgSectors % 63));
319 }
320
321 // Add +1 for our superblock which is at the end
322 if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700323 SLOGE("ASEC image file creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800324 return -1;
325 }
326
San Mehatd9a4e352010-03-12 13:32:47 -0800327 char idHash[33];
328 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700329 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800330 unlink(asecFileName);
331 return -1;
332 }
333
San Mehata19b2502010-01-06 10:33:53 -0800334 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800335 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700336 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800337 unlink(asecFileName);
338 return -1;
339 }
340
San Mehatb78a32c2010-01-10 13:02:12 -0800341 char dmDevice[255];
342 bool cleanupDm = false;
San Mehata19b2502010-01-06 10:33:53 -0800343
San Mehatb78a32c2010-01-10 13:02:12 -0800344 if (strcmp(key, "none")) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800345 // XXX: This is all we support for now
346 sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
San Mehatd9a4e352010-03-12 13:32:47 -0800347 if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
San Mehatb78a32c2010-01-10 13:02:12 -0800348 sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700349 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800350 Loop::destroyByDevice(loopDevice);
351 unlink(asecFileName);
352 return -1;
353 }
354 cleanupDm = true;
355 } else {
San Mehatfcf24fe2010-03-03 12:37:32 -0800356 sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
San Mehatb78a32c2010-01-10 13:02:12 -0800357 strcpy(dmDevice, loopDevice);
358 }
359
San Mehatfcf24fe2010-03-03 12:37:32 -0800360 /*
361 * Drop down the superblock at the end of the file
362 */
363
364 int sbfd = open(loopDevice, O_RDWR);
365 if (sbfd < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700366 SLOGE("Failed to open new DM device for superblock write (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800367 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800368 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800369 }
370 Loop::destroyByDevice(loopDevice);
371 unlink(asecFileName);
372 return -1;
373 }
374
375 if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
376 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700377 SLOGE("Failed to lseek for superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800378 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800379 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800380 }
381 Loop::destroyByDevice(loopDevice);
382 unlink(asecFileName);
383 return -1;
384 }
385
386 if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) {
387 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700388 SLOGE("Failed to write superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800389 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800390 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800391 }
392 Loop::destroyByDevice(loopDevice);
393 unlink(asecFileName);
394 return -1;
395 }
396 close(sbfd);
397
Kenny Root344ca102012-04-03 17:23:01 -0700398 if (wantFilesystem) {
399 int formatStatus;
400 if (usingExt4) {
401 formatStatus = Ext4::format(dmDevice);
402 } else {
403 formatStatus = Fat::format(dmDevice, numImgSectors);
San Mehatb78a32c2010-01-10 13:02:12 -0800404 }
San Mehata19b2502010-01-06 10:33:53 -0800405
Kenny Root344ca102012-04-03 17:23:01 -0700406 if (formatStatus < 0) {
407 SLOGE("ASEC fs format failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800408 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800409 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800410 }
San Mehateb13a902010-01-07 12:12:50 -0800411 Loop::destroyByDevice(loopDevice);
412 unlink(asecFileName);
413 return -1;
414 }
Kenny Root344ca102012-04-03 17:23:01 -0700415
San Mehata1091cb2010-02-28 20:17:20 -0800416 char mountPoint[255];
San Mehata19b2502010-01-06 10:33:53 -0800417
San Mehata1091cb2010-02-28 20:17:20 -0800418 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
Kenny Root344ca102012-04-03 17:23:01 -0700419 if (mkdir(mountPoint, 0000)) {
San Mehata1091cb2010-02-28 20:17:20 -0800420 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -0700421 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800422 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800423 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800424 }
425 Loop::destroyByDevice(loopDevice);
426 unlink(asecFileName);
427 return -1;
428 }
San Mehatb78a32c2010-01-10 13:02:12 -0800429 }
San Mehata1091cb2010-02-28 20:17:20 -0800430
Kenny Root344ca102012-04-03 17:23:01 -0700431 int mountStatus;
432 if (usingExt4) {
433 mountStatus = Ext4::doMount(dmDevice, mountPoint, false, false, false);
434 } else {
435 mountStatus = Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid, 0, 0000,
436 false);
437 }
438
439 if (mountStatus) {
San Mehat97ac40e2010-03-24 10:24:19 -0700440 SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800441 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800442 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800443 }
444 Loop::destroyByDevice(loopDevice);
445 unlink(asecFileName);
446 return -1;
447 }
Kenny Root344ca102012-04-03 17:23:01 -0700448
449 if (usingExt4) {
450 int dirfd = open(mountPoint, O_DIRECTORY);
451 if (dirfd >= 0) {
452 if (fchown(dirfd, ownerUid, AID_SYSTEM)
453 || fchmod(dirfd, S_IRUSR | S_IWUSR | S_IXUSR | S_ISGID | S_IRGRP | S_IXGRP)) {
454 SLOGI("Cannot chown/chmod new ASEC mount point %s", mountPoint);
455 }
456 close(dirfd);
457 }
458 }
San Mehata1091cb2010-02-28 20:17:20 -0800459 } else {
San Mehat97ac40e2010-03-24 10:24:19 -0700460 SLOGI("Created raw secure container %s (no filesystem)", id);
San Mehata19b2502010-01-06 10:33:53 -0800461 }
San Mehat88705162010-01-15 09:26:28 -0800462
Kenny Rootcbacf782010-09-24 15:11:48 -0700463 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehata19b2502010-01-06 10:33:53 -0800464 return 0;
465}
466
467int VolumeManager::finalizeAsec(const char *id) {
468 char asecFileName[255];
469 char loopDevice[255];
470 char mountPoint[255];
471
Nick Kralevich0de7c612014-01-27 14:58:06 -0800472 if (!isLegalAsecId(id)) {
473 SLOGE("finalizeAsec: Invalid asec id \"%s\"", id);
474 errno = EINVAL;
475 return -1;
476 }
477
Kenny Root344ca102012-04-03 17:23:01 -0700478 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
479 SLOGE("Couldn't find ASEC %s", id);
480 return -1;
481 }
San Mehata19b2502010-01-06 10:33:53 -0800482
San Mehatd9a4e352010-03-12 13:32:47 -0800483 char idHash[33];
484 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700485 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800486 return -1;
487 }
488
489 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700490 SLOGE("Unable to finalize %s (%s)", id, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800491 return -1;
492 }
493
Kenny Root344ca102012-04-03 17:23:01 -0700494 unsigned int nr_sec = 0;
495 struct asec_superblock sb;
496
497 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
498 return -1;
499 }
500
San Mehat3bb60202010-02-19 18:14:36 -0800501 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
Kenny Root344ca102012-04-03 17:23:01 -0700502
503 int result = 0;
504 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
505 result = Ext4::doMount(loopDevice, mountPoint, true, true, true);
506 } else {
507 result = Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false);
508 }
509
510 if (result) {
San Mehat97ac40e2010-03-24 10:24:19 -0700511 SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800512 return -1;
513 }
514
San Mehatd9a4e352010-03-12 13:32:47 -0800515 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700516 SLOGD("ASEC %s finalized", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800517 }
San Mehata19b2502010-01-06 10:33:53 -0800518 return 0;
519}
520
Kenny Root344ca102012-04-03 17:23:01 -0700521int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* filename) {
522 char asecFileName[255];
523 char loopDevice[255];
524 char mountPoint[255];
525
526 if (gid < AID_APP) {
527 SLOGE("Group ID is not in application range");
528 return -1;
529 }
530
Nick Kralevich0de7c612014-01-27 14:58:06 -0800531 if (!isLegalAsecId(id)) {
532 SLOGE("fixupAsecPermissions: Invalid asec id \"%s\"", id);
533 errno = EINVAL;
534 return -1;
535 }
536
Kenny Root344ca102012-04-03 17:23:01 -0700537 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
538 SLOGE("Couldn't find ASEC %s", id);
539 return -1;
540 }
541
542 char idHash[33];
543 if (!asecHash(id, idHash, sizeof(idHash))) {
544 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
545 return -1;
546 }
547
548 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
549 SLOGE("Unable fix permissions during lookup on %s (%s)", id, strerror(errno));
550 return -1;
551 }
552
553 unsigned int nr_sec = 0;
554 struct asec_superblock sb;
555
556 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
557 return -1;
558 }
559
560 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
561
562 int result = 0;
563 if ((sb.c_opts & ASEC_SB_C_OPTS_EXT4) == 0) {
564 return 0;
565 }
566
567 int ret = Ext4::doMount(loopDevice, mountPoint,
568 false /* read-only */,
569 true /* remount */,
570 false /* executable */);
571 if (ret) {
572 SLOGE("Unable remount to fix permissions for %s (%s)", id, strerror(errno));
573 return -1;
574 }
575
576 char *paths[] = { mountPoint, NULL };
577
578 FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL);
579 if (fts) {
580 // Traverse the entire hierarchy and chown to system UID.
581 for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
582 // We don't care about the lost+found directory.
583 if (!strcmp(ftsent->fts_name, "lost+found")) {
584 continue;
585 }
586
587 /*
588 * There can only be one file marked as private right now.
589 * This should be more robust, but it satisfies the requirements
590 * we have for right now.
591 */
592 const bool privateFile = !strcmp(ftsent->fts_name, filename);
593
594 int fd = open(ftsent->fts_accpath, O_NOFOLLOW);
595 if (fd < 0) {
596 SLOGE("Couldn't open file %s: %s", ftsent->fts_accpath, strerror(errno));
597 result = -1;
598 continue;
599 }
600
601 result |= fchown(fd, AID_SYSTEM, privateFile? gid : AID_SYSTEM);
602
603 if (ftsent->fts_info & FTS_D) {
Kenny Root1a673c82012-05-10 16:45:29 -0700604 result |= fchmod(fd, 0755);
Kenny Root348c8ab2012-05-10 15:39:53 -0700605 } else if (ftsent->fts_info & FTS_F) {
Kenny Root344ca102012-04-03 17:23:01 -0700606 result |= fchmod(fd, privateFile ? 0640 : 0644);
607 }
608 close(fd);
609 }
610 fts_close(fts);
611
612 // Finally make the directory readable by everyone.
613 int dirfd = open(mountPoint, O_DIRECTORY);
614 if (dirfd < 0 || fchmod(dirfd, 0755)) {
615 SLOGE("Couldn't change owner of existing directory %s: %s", mountPoint, strerror(errno));
616 result |= -1;
617 }
618 close(dirfd);
619 } else {
620 result |= -1;
621 }
622
623 result |= Ext4::doMount(loopDevice, mountPoint,
624 true /* read-only */,
625 true /* remount */,
626 true /* execute */);
627
628 if (result) {
629 SLOGE("ASEC fix permissions failed (%s)", strerror(errno));
630 return -1;
631 }
632
633 if (mDebug) {
634 SLOGD("ASEC %s permissions fixed", id);
635 }
636 return 0;
637}
638
San Mehat048b0802010-01-23 08:17:06 -0800639int VolumeManager::renameAsec(const char *id1, const char *id2) {
Kenny Root344ca102012-04-03 17:23:01 -0700640 char asecFilename1[255];
San Mehat048b0802010-01-23 08:17:06 -0800641 char *asecFilename2;
642 char mountPoint[255];
643
Kenny Root344ca102012-04-03 17:23:01 -0700644 const char *dir;
645
Nick Kralevich0de7c612014-01-27 14:58:06 -0800646 if (!isLegalAsecId(id1)) {
647 SLOGE("renameAsec: Invalid asec id1 \"%s\"", id1);
648 errno = EINVAL;
649 return -1;
650 }
651
652 if (!isLegalAsecId(id2)) {
653 SLOGE("renameAsec: Invalid asec id2 \"%s\"", id2);
654 errno = EINVAL;
655 return -1;
656 }
657
Kenny Root344ca102012-04-03 17:23:01 -0700658 if (findAsec(id1, asecFilename1, sizeof(asecFilename1), &dir)) {
659 SLOGE("Couldn't find ASEC %s", id1);
660 return -1;
661 }
662
663 asprintf(&asecFilename2, "%s/%s.asec", dir, id2);
San Mehat048b0802010-01-23 08:17:06 -0800664
San Mehat3bb60202010-02-19 18:14:36 -0800665 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
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
San Mehat96956ed2010-02-24 08:42:51 -0800672 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2);
673 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700674 SLOGW("Rename attempt when dst mounted");
San Mehat96956ed2010-02-24 08:42:51 -0800675 errno = EBUSY;
676 goto out_err;
677 }
678
San Mehat048b0802010-01-23 08:17:06 -0800679 if (!access(asecFilename2, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700680 SLOGE("Rename attempt when dst exists");
San Mehat048b0802010-01-23 08:17:06 -0800681 errno = EADDRINUSE;
682 goto out_err;
683 }
684
685 if (rename(asecFilename1, asecFilename2)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700686 SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
San Mehat048b0802010-01-23 08:17:06 -0800687 goto out_err;
688 }
689
San Mehat048b0802010-01-23 08:17:06 -0800690 free(asecFilename2);
691 return 0;
692
693out_err:
San Mehat048b0802010-01-23 08:17:06 -0800694 free(asecFilename2);
695 return -1;
696}
697
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700698#define UNMOUNT_RETRIES 5
699#define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
San Mehat4ba89482010-02-18 09:00:18 -0800700int VolumeManager::unmountAsec(const char *id, bool force) {
San Mehata19b2502010-01-06 10:33:53 -0800701 char asecFileName[255];
702 char mountPoint[255];
703
Nick Kralevich0de7c612014-01-27 14:58:06 -0800704 if (!isLegalAsecId(id)) {
705 SLOGE("unmountAsec: Invalid asec id \"%s\"", id);
706 errno = EINVAL;
707 return -1;
708 }
709
Kenny Root344ca102012-04-03 17:23:01 -0700710 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
711 SLOGE("Couldn't find ASEC %s", id);
712 return -1;
713 }
714
San Mehat3bb60202010-02-19 18:14:36 -0800715 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800716
San Mehatd9a4e352010-03-12 13:32:47 -0800717 char idHash[33];
718 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700719 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800720 return -1;
721 }
722
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700723 return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
724}
725
Kenny Root508c0e12010-07-12 09:59:49 -0700726int VolumeManager::unmountObb(const char *fileName, bool force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700727 char mountPoint[255];
728
729 char idHash[33];
730 if (!asecHash(fileName, idHash, sizeof(idHash))) {
731 SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
732 return -1;
733 }
734
735 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
736
737 return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
738}
739
740int VolumeManager::unmountLoopImage(const char *id, const char *idHash,
741 const char *fileName, const char *mountPoint, bool force) {
San Mehat0586d542010-01-12 15:38:59 -0800742 if (!isMountpointMounted(mountPoint)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700743 SLOGE("Unmount request for %s when not mounted", id);
Kenny Root918e5f92010-09-30 18:00:52 -0700744 errno = ENOENT;
San Mehatb78a32c2010-01-10 13:02:12 -0800745 return -1;
746 }
San Mehat23969932010-01-09 07:08:06 -0800747
San Mehatb78a32c2010-01-10 13:02:12 -0800748 int i, rc;
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700749 for (i = 1; i <= UNMOUNT_RETRIES; i++) {
San Mehatb78a32c2010-01-10 13:02:12 -0800750 rc = umount(mountPoint);
751 if (!rc) {
752 break;
San Mehata19b2502010-01-06 10:33:53 -0800753 }
San Mehatb78a32c2010-01-10 13:02:12 -0800754 if (rc && (errno == EINVAL || errno == ENOENT)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700755 SLOGI("Container %s unmounted OK", id);
San Mehatb78a32c2010-01-10 13:02:12 -0800756 rc = 0;
757 break;
San Mehata19b2502010-01-06 10:33:53 -0800758 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700759 SLOGW("%s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -0800760 id, i, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800761
San Mehat4ba89482010-02-18 09:00:18 -0800762 int action = 0; // default is to just complain
763
764 if (force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700765 if (i > (UNMOUNT_RETRIES - 2))
San Mehat4ba89482010-02-18 09:00:18 -0800766 action = 2; // SIGKILL
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700767 else if (i > (UNMOUNT_RETRIES - 3))
San Mehat4ba89482010-02-18 09:00:18 -0800768 action = 1; // SIGHUP
769 }
San Mehat8c940ef2010-02-13 14:19:53 -0800770
San Mehat586536c2010-02-16 17:12:00 -0800771 Process::killProcessesWithOpenFiles(mountPoint, action);
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700772 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehatb78a32c2010-01-10 13:02:12 -0800773 }
774
775 if (rc) {
San Mehat4ba89482010-02-18 09:00:18 -0800776 errno = EBUSY;
San Mehat97ac40e2010-03-24 10:24:19 -0700777 SLOGE("Failed to unmount container %s (%s)", id, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800778 return -1;
779 }
780
San Mehat12f4b892010-02-24 11:43:22 -0800781 int retries = 10;
782
783 while(retries--) {
784 if (!rmdir(mountPoint)) {
785 break;
786 }
787
San Mehat97ac40e2010-03-24 10:24:19 -0700788 SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700789 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehat12f4b892010-02-24 11:43:22 -0800790 }
791
792 if (!retries) {
San Mehat97ac40e2010-03-24 10:24:19 -0700793 SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
San Mehatf5c61982010-02-03 11:04:46 -0800794 }
San Mehat88705162010-01-15 09:26:28 -0800795
San Mehatd9a4e352010-03-12 13:32:47 -0800796 if (Devmapper::destroy(idHash) && errno != ENXIO) {
San Mehat97ac40e2010-03-24 10:24:19 -0700797 SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800798 }
799
800 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800801 if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800802 Loop::destroyByDevice(loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800803 } else {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700804 SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800805 }
San Mehat88705162010-01-15 09:26:28 -0800806
807 AsecIdCollection::iterator it;
808 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
Kenny Rootcbacf782010-09-24 15:11:48 -0700809 ContainerData* cd = *it;
810 if (!strcmp(cd->id, id)) {
San Mehat88705162010-01-15 09:26:28 -0800811 free(*it);
812 mActiveContainers->erase(it);
813 break;
814 }
815 }
816 if (it == mActiveContainers->end()) {
San Mehat97ac40e2010-03-24 10:24:19 -0700817 SLOGW("mActiveContainers is inconsistent!");
San Mehat88705162010-01-15 09:26:28 -0800818 }
San Mehatb78a32c2010-01-10 13:02:12 -0800819 return 0;
820}
821
San Mehat4ba89482010-02-18 09:00:18 -0800822int VolumeManager::destroyAsec(const char *id, bool force) {
San Mehatb78a32c2010-01-10 13:02:12 -0800823 char asecFileName[255];
824 char mountPoint[255];
825
Nick Kralevich0de7c612014-01-27 14:58:06 -0800826 if (!isLegalAsecId(id)) {
827 SLOGE("destroyAsec: Invalid asec id \"%s\"", id);
828 errno = EINVAL;
829 return -1;
830 }
831
Kenny Root344ca102012-04-03 17:23:01 -0700832 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
833 SLOGE("Couldn't find ASEC %s", id);
834 return -1;
835 }
836
San Mehat55013f72010-02-24 12:12:34 -0800837 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatb78a32c2010-01-10 13:02:12 -0800838
San Mehat0586d542010-01-12 15:38:59 -0800839 if (isMountpointMounted(mountPoint)) {
San Mehatd9a4e352010-03-12 13:32:47 -0800840 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700841 SLOGD("Unmounting container before destroy");
San Mehatd9a4e352010-03-12 13:32:47 -0800842 }
San Mehat4ba89482010-02-18 09:00:18 -0800843 if (unmountAsec(id, force)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700844 SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800845 return -1;
846 }
847 }
San Mehata19b2502010-01-06 10:33:53 -0800848
San Mehat0586d542010-01-12 15:38:59 -0800849 if (unlink(asecFileName)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700850 SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800851 return -1;
852 }
San Mehata19b2502010-01-06 10:33:53 -0800853
San Mehatd9a4e352010-03-12 13:32:47 -0800854 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700855 SLOGD("ASEC %s destroyed", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800856 }
San Mehata19b2502010-01-06 10:33:53 -0800857 return 0;
858}
859
Nick Kralevich0de7c612014-01-27 14:58:06 -0800860/*
861 * Legal ASEC ids consist of alphanumeric characters, '-',
862 * '_', or '.'. ".." is not allowed. The first or last character
863 * of the ASEC id cannot be '.' (dot).
864 */
865bool VolumeManager::isLegalAsecId(const char *id) const {
866 size_t i;
867 size_t len = strlen(id);
868
869 if (len == 0) {
870 return false;
871 }
872 if ((id[0] == '.') || (id[len - 1] == '.')) {
873 return false;
874 }
875
876 for (i = 0; i < len; i++) {
877 if (id[i] == '.') {
878 // i=0 is guaranteed never to have a dot. See above.
879 if (id[i-1] == '.') return false;
880 continue;
881 }
882 if (id[i] == '_' || id[i] == '-') continue;
883 if (id[i] >= 'a' && id[i] <= 'z') continue;
884 if (id[i] >= 'A' && id[i] <= 'Z') continue;
885 if (id[i] >= '0' && id[i] <= '9') continue;
886 return false;
887 }
888
889 return true;
890}
891
Kenny Root344ca102012-04-03 17:23:01 -0700892bool VolumeManager::isAsecInDirectory(const char *dir, const char *asecName) const {
893 int dirfd = open(dir, O_DIRECTORY);
894 if (dirfd < 0) {
895 SLOGE("Couldn't open internal ASEC dir (%s)", strerror(errno));
896 return -1;
897 }
898
899 bool ret = false;
900
901 if (!faccessat(dirfd, asecName, F_OK, AT_SYMLINK_NOFOLLOW)) {
902 ret = true;
903 }
904
905 close(dirfd);
906
907 return ret;
908}
909
910int VolumeManager::findAsec(const char *id, char *asecPath, size_t asecPathLen,
911 const char **directory) const {
912 int dirfd, fd;
913 const int idLen = strlen(id);
914 char *asecName;
915
Nick Kralevich0de7c612014-01-27 14:58:06 -0800916 if (!isLegalAsecId(id)) {
917 SLOGE("findAsec: Invalid asec id \"%s\"", id);
918 errno = EINVAL;
919 return -1;
920 }
921
Kenny Root344ca102012-04-03 17:23:01 -0700922 if (asprintf(&asecName, "%s.asec", id) < 0) {
923 SLOGE("Couldn't allocate string to write ASEC name");
924 return -1;
925 }
926
927 const char *dir;
928 if (isAsecInDirectory(Volume::SEC_ASECDIR_INT, asecName)) {
929 dir = Volume::SEC_ASECDIR_INT;
930 } else if (isAsecInDirectory(Volume::SEC_ASECDIR_EXT, asecName)) {
931 dir = Volume::SEC_ASECDIR_EXT;
932 } else {
933 free(asecName);
934 return -1;
935 }
936
937 if (directory != NULL) {
938 *directory = dir;
939 }
940
941 if (asecPath != NULL) {
942 int written = snprintf(asecPath, asecPathLen, "%s/%s", dir, asecName);
943 if (written < 0 || static_cast<size_t>(written) >= asecPathLen) {
944 free(asecName);
945 return -1;
946 }
947 }
948
949 free(asecName);
950 return 0;
951}
952
San Mehata19b2502010-01-06 10:33:53 -0800953int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
954 char asecFileName[255];
955 char mountPoint[255];
956
Nick Kralevich0de7c612014-01-27 14:58:06 -0800957 if (!isLegalAsecId(id)) {
958 SLOGE("mountAsec: Invalid asec id \"%s\"", id);
959 errno = EINVAL;
960 return -1;
961 }
962
Kenny Root344ca102012-04-03 17:23:01 -0700963 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
964 SLOGE("Couldn't find ASEC %s", id);
965 return -1;
966 }
967
San Mehat3bb60202010-02-19 18:14:36 -0800968 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800969
970 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700971 SLOGE("ASEC %s already mounted", id);
San Mehata19b2502010-01-06 10:33:53 -0800972 errno = EBUSY;
973 return -1;
974 }
975
San Mehatd9a4e352010-03-12 13:32:47 -0800976 char idHash[33];
977 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700978 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800979 return -1;
980 }
Kenny Root7b18a7b2010-03-15 13:13:41 -0700981
San Mehata19b2502010-01-06 10:33:53 -0800982 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800983 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
984 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700985 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800986 return -1;
987 }
San Mehatd9a4e352010-03-12 13:32:47 -0800988 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700989 SLOGD("New loop device created at %s", loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800990 }
San Mehatb78a32c2010-01-10 13:02:12 -0800991 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800992 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700993 SLOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800994 }
San Mehatb78a32c2010-01-10 13:02:12 -0800995 }
996
997 char dmDevice[255];
998 bool cleanupDm = false;
San Mehatfcf24fe2010-03-03 12:37:32 -0800999 int fd;
1000 unsigned int nr_sec = 0;
San Mehatfcf24fe2010-03-03 12:37:32 -08001001 struct asec_superblock sb;
San Mehatfcf24fe2010-03-03 12:37:32 -08001002
Kenny Root344ca102012-04-03 17:23:01 -07001003 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
1004 return -1;
1005 }
San Mehatfcf24fe2010-03-03 12:37:32 -08001006
San Mehatd9a4e352010-03-12 13:32:47 -08001007 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001008 SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatd9a4e352010-03-12 13:32:47 -08001009 }
San Mehatfcf24fe2010-03-03 12:37:32 -08001010 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
San Mehat97ac40e2010-03-24 10:24:19 -07001011 SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatfcf24fe2010-03-03 12:37:32 -08001012 Loop::destroyByDevice(loopDevice);
1013 errno = EMEDIUMTYPE;
1014 return -1;
1015 }
1016 nr_sec--; // We don't want the devmapping to extend onto our superblock
1017
San Mehatb78a32c2010-01-10 13:02:12 -08001018 if (strcmp(key, "none")) {
San Mehatd9a4e352010-03-12 13:32:47 -08001019 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
1020 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
San Mehatb78a32c2010-01-10 13:02:12 -08001021 dmDevice, sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001022 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001023 Loop::destroyByDevice(loopDevice);
1024 return -1;
1025 }
San Mehatd9a4e352010-03-12 13:32:47 -08001026 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001027 SLOGD("New devmapper instance created at %s", dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -08001028 }
San Mehatb78a32c2010-01-10 13:02:12 -08001029 } else {
San Mehatd9a4e352010-03-12 13:32:47 -08001030 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001031 SLOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -08001032 }
San Mehatb78a32c2010-01-10 13:02:12 -08001033 }
1034 cleanupDm = true;
1035 } else {
1036 strcpy(dmDevice, loopDevice);
San Mehata19b2502010-01-06 10:33:53 -08001037 }
1038
Kenny Root344ca102012-04-03 17:23:01 -07001039 if (mkdir(mountPoint, 0000)) {
San Mehatb78a32c2010-01-10 13:02:12 -08001040 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -07001041 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001042 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -08001043 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -08001044 }
1045 Loop::destroyByDevice(loopDevice);
1046 return -1;
1047 }
San Mehata19b2502010-01-06 10:33:53 -08001048 }
1049
Kenny Rootcdc2a1c2012-05-03 13:49:46 -07001050 /*
1051 * The device mapper node needs to be created. Sometimes it takes a
1052 * while. Wait for up to 1 second. We could also inspect incoming uevents,
1053 * but that would take more effort.
1054 */
1055 int tries = 25;
1056 while (tries--) {
1057 if (!access(dmDevice, F_OK) || errno != ENOENT) {
1058 break;
1059 }
1060 usleep(40 * 1000);
1061 }
1062
Kenny Root344ca102012-04-03 17:23:01 -07001063 int result;
1064 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
1065 result = Ext4::doMount(dmDevice, mountPoint, true, false, true);
1066 } else {
1067 result = Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0, 0222, false);
1068 }
1069
1070 if (result) {
San Mehat97ac40e2010-03-24 10:24:19 -07001071 SLOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001072 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -08001073 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -08001074 }
1075 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -08001076 return -1;
1077 }
1078
Kenny Rootcbacf782010-09-24 15:11:48 -07001079 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehatd9a4e352010-03-12 13:32:47 -08001080 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001081 SLOGD("ASEC %s mounted", id);
San Mehatd9a4e352010-03-12 13:32:47 -08001082 }
San Mehata19b2502010-01-06 10:33:53 -08001083 return 0;
1084}
1085
Kenny Rooteacf7e02012-08-09 11:28:37 -07001086Volume* VolumeManager::getVolumeForFile(const char *fileName) {
1087 VolumeCollection::iterator i;
1088
1089 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1090 const char* mountPoint = (*i)->getMountpoint();
1091 if (!strncmp(fileName, mountPoint, strlen(mountPoint))) {
1092 return *i;
1093 }
1094 }
1095
1096 return NULL;
1097}
1098
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001099/**
1100 * Mounts an image file <code>img</code>.
1101 */
Kenny Root508c0e12010-07-12 09:59:49 -07001102int VolumeManager::mountObb(const char *img, const char *key, int ownerUid) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001103 char mountPoint[255];
1104
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001105 char idHash[33];
1106 if (!asecHash(img, idHash, sizeof(idHash))) {
1107 SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
1108 return -1;
1109 }
1110
1111 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
1112
1113 if (isMountpointMounted(mountPoint)) {
1114 SLOGE("Image %s already mounted", img);
1115 errno = EBUSY;
1116 return -1;
1117 }
1118
1119 char loopDevice[255];
1120 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
1121 if (Loop::create(idHash, img, loopDevice, sizeof(loopDevice))) {
1122 SLOGE("Image loop device creation failed (%s)", strerror(errno));
1123 return -1;
1124 }
1125 if (mDebug) {
1126 SLOGD("New loop device created at %s", loopDevice);
1127 }
1128 } else {
1129 if (mDebug) {
1130 SLOGD("Found active loopback for %s at %s", img, loopDevice);
1131 }
1132 }
1133
1134 char dmDevice[255];
1135 bool cleanupDm = false;
1136 int fd;
1137 unsigned int nr_sec = 0;
1138
1139 if ((fd = open(loopDevice, O_RDWR)) < 0) {
1140 SLOGE("Failed to open loopdevice (%s)", strerror(errno));
1141 Loop::destroyByDevice(loopDevice);
1142 return -1;
1143 }
1144
1145 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
1146 SLOGE("Failed to get loop size (%s)", strerror(errno));
1147 Loop::destroyByDevice(loopDevice);
1148 close(fd);
1149 return -1;
1150 }
1151
1152 close(fd);
1153
1154 if (strcmp(key, "none")) {
1155 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
1156 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
1157 dmDevice, sizeof(dmDevice))) {
1158 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
1159 Loop::destroyByDevice(loopDevice);
1160 return -1;
1161 }
1162 if (mDebug) {
1163 SLOGD("New devmapper instance created at %s", dmDevice);
1164 }
1165 } else {
1166 if (mDebug) {
1167 SLOGD("Found active devmapper for %s at %s", img, dmDevice);
1168 }
1169 }
1170 cleanupDm = true;
1171 } else {
1172 strcpy(dmDevice, loopDevice);
1173 }
1174
1175 if (mkdir(mountPoint, 0755)) {
1176 if (errno != EEXIST) {
1177 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
1178 if (cleanupDm) {
1179 Devmapper::destroy(idHash);
1180 }
1181 Loop::destroyByDevice(loopDevice);
1182 return -1;
1183 }
1184 }
1185
Kenny Roota3e06082010-08-27 08:31:35 -07001186 if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0,
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001187 0227, false)) {
1188 SLOGE("Image mount failed (%s)", strerror(errno));
1189 if (cleanupDm) {
1190 Devmapper::destroy(idHash);
1191 }
1192 Loop::destroyByDevice(loopDevice);
1193 return -1;
1194 }
1195
Kenny Rootcbacf782010-09-24 15:11:48 -07001196 mActiveContainers->push_back(new ContainerData(strdup(img), OBB));
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001197 if (mDebug) {
1198 SLOGD("Image %s mounted", img);
1199 }
1200 return 0;
1201}
1202
San Mehat49e2bce2009-10-12 16:29:01 -07001203int VolumeManager::mountVolume(const char *label) {
1204 Volume *v = lookupVolume(label);
1205
1206 if (!v) {
1207 errno = ENOENT;
1208 return -1;
1209 }
1210
San Mehata2677e42009-12-13 10:40:18 -08001211 return v->mountVol();
1212}
1213
Kenny Root508c0e12010-07-12 09:59:49 -07001214int VolumeManager::listMountedObbs(SocketClient* cli) {
1215 char device[256];
1216 char mount_path[256];
1217 char rest[256];
1218 FILE *fp;
1219 char line[1024];
1220
1221 if (!(fp = fopen("/proc/mounts", "r"))) {
1222 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
1223 return -1;
1224 }
1225
1226 // Create a string to compare against that has a trailing slash
Kenny Rooteacf7e02012-08-09 11:28:37 -07001227 int loopDirLen = strlen(Volume::LOOPDIR);
Kenny Root508c0e12010-07-12 09:59:49 -07001228 char loopDir[loopDirLen + 2];
1229 strcpy(loopDir, Volume::LOOPDIR);
1230 loopDir[loopDirLen++] = '/';
1231 loopDir[loopDirLen] = '\0';
1232
1233 while(fgets(line, sizeof(line), fp)) {
1234 line[strlen(line)-1] = '\0';
1235
1236 /*
1237 * Should look like:
1238 * /dev/block/loop0 /mnt/obb/fc99df1323fd36424f864dcb76b76d65 ...
1239 */
1240 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1241
1242 if (!strncmp(mount_path, loopDir, loopDirLen)) {
1243 int fd = open(device, O_RDONLY);
1244 if (fd >= 0) {
1245 struct loop_info64 li;
1246 if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
1247 cli->sendMsg(ResponseCode::AsecListResult,
1248 (const char*) li.lo_file_name, false);
1249 }
1250 close(fd);
1251 }
1252 }
1253 }
1254
1255 fclose(fp);
1256 return 0;
1257}
1258
San Mehateba65e92010-01-29 05:15:16 -08001259int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
1260 Volume *v = lookupVolume(label);
1261
1262 if (!v) {
1263 errno = ENOENT;
1264 return -1;
1265 }
1266
1267 if (strcmp(method, "ums")) {
1268 errno = ENOSYS;
1269 return -1;
1270 }
1271
1272 if (v->getState() != Volume::State_Shared) {
San Mehateba65e92010-01-29 05:15:16 -08001273 *enabled = false;
San Mehatb9aed742010-02-04 15:07:01 -08001274 } else {
1275 *enabled = true;
San Mehateba65e92010-01-29 05:15:16 -08001276 }
1277 return 0;
1278}
1279
San Mehata2677e42009-12-13 10:40:18 -08001280int VolumeManager::shareVolume(const char *label, const char *method) {
1281 Volume *v = lookupVolume(label);
1282
1283 if (!v) {
1284 errno = ENOENT;
1285 return -1;
1286 }
1287
1288 /*
1289 * Eventually, we'll want to support additional share back-ends,
1290 * some of which may work while the media is mounted. For now,
1291 * we just support UMS
1292 */
1293 if (strcmp(method, "ums")) {
1294 errno = ENOSYS;
1295 return -1;
1296 }
1297
1298 if (v->getState() == Volume::State_NoMedia) {
1299 errno = ENODEV;
1300 return -1;
1301 }
1302
San Mehat49e2bce2009-10-12 16:29:01 -07001303 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -08001304 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -07001305 errno = EBUSY;
1306 return -1;
1307 }
1308
Ken Sumrall3b170052011-07-11 15:38:57 -07001309 if (mVolManagerDisabled) {
1310 errno = EBUSY;
1311 return -1;
1312 }
1313
Mike Lockwood2dfe2972010-09-17 18:50:51 -04001314 dev_t d = v->getShareDevice();
San Mehata2677e42009-12-13 10:40:18 -08001315 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
1316 // This volume does not support raw disk access
1317 errno = EINVAL;
1318 return -1;
1319 }
1320
1321 int fd;
1322 char nodepath[255];
1323 snprintf(nodepath,
1324 sizeof(nodepath), "/dev/block/vold/%d:%d",
1325 MAJOR(d), MINOR(d));
1326
Mike Lockwood97f2fc12011-06-07 10:51:38 -07001327 if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001328 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001329 return -1;
1330 }
1331
1332 if (write(fd, nodepath, strlen(nodepath)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001333 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001334 close(fd);
1335 return -1;
1336 }
1337
1338 close(fd);
1339 v->handleVolumeShared();
Mike Lockwooda28056b2010-10-28 15:21:24 -04001340 if (mUmsSharingCount++ == 0) {
1341 FILE* fp;
1342 mSavedDirtyRatio = -1; // in case we fail
1343 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1344 char line[16];
1345 if (fgets(line, sizeof(line), fp) && sscanf(line, "%d", &mSavedDirtyRatio)) {
1346 fprintf(fp, "%d\n", mUmsDirtyRatio);
1347 } else {
1348 SLOGE("Failed to read dirty_ratio (%s)", strerror(errno));
1349 }
1350 fclose(fp);
1351 } else {
1352 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1353 }
1354 }
San Mehata2677e42009-12-13 10:40:18 -08001355 return 0;
1356}
1357
1358int VolumeManager::unshareVolume(const char *label, const char *method) {
1359 Volume *v = lookupVolume(label);
1360
1361 if (!v) {
1362 errno = ENOENT;
1363 return -1;
1364 }
1365
1366 if (strcmp(method, "ums")) {
1367 errno = ENOSYS;
1368 return -1;
1369 }
1370
1371 if (v->getState() != Volume::State_Shared) {
1372 errno = EINVAL;
1373 return -1;
1374 }
1375
San Mehata2677e42009-12-13 10:40:18 -08001376 int fd;
Mike Lockwood97f2fc12011-06-07 10:51:38 -07001377 if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001378 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001379 return -1;
1380 }
1381
1382 char ch = 0;
1383 if (write(fd, &ch, 1) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001384 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001385 close(fd);
1386 return -1;
1387 }
1388
1389 close(fd);
1390 v->handleVolumeUnshared();
Mike Lockwooda28056b2010-10-28 15:21:24 -04001391 if (--mUmsSharingCount == 0 && mSavedDirtyRatio != -1) {
1392 FILE* fp;
1393 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1394 fprintf(fp, "%d\n", mSavedDirtyRatio);
1395 fclose(fp);
1396 } else {
1397 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1398 }
1399 mSavedDirtyRatio = -1;
1400 }
San Mehata2677e42009-12-13 10:40:18 -08001401 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -07001402}
1403
Ken Sumrall3b170052011-07-11 15:38:57 -07001404extern "C" int vold_disableVol(const char *label) {
Ken Sumrall29d8da82011-05-18 17:20:07 -07001405 VolumeManager *vm = VolumeManager::Instance();
Ken Sumrall3b170052011-07-11 15:38:57 -07001406 vm->disableVolumeManager();
1407 vm->unshareVolume(label, "ums");
Ken Sumrall0b8b5972011-08-31 16:14:23 -07001408 return vm->unmountVolume(label, true, false);
Ken Sumrall29d8da82011-05-18 17:20:07 -07001409}
1410
1411extern "C" int vold_getNumDirectVolumes(void) {
1412 VolumeManager *vm = VolumeManager::Instance();
1413 return vm->getNumDirectVolumes();
1414}
1415
1416int VolumeManager::getNumDirectVolumes(void) {
1417 VolumeCollection::iterator i;
1418 int n=0;
1419
1420 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1421 if ((*i)->getShareDevice() != (dev_t)0) {
1422 n++;
1423 }
1424 }
1425 return n;
1426}
1427
1428extern "C" int vold_getDirectVolumeList(struct volume_info *vol_list) {
1429 VolumeManager *vm = VolumeManager::Instance();
1430 return vm->getDirectVolumeList(vol_list);
1431}
1432
1433int VolumeManager::getDirectVolumeList(struct volume_info *vol_list) {
1434 VolumeCollection::iterator i;
1435 int n=0;
1436 dev_t d;
1437
1438 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1439 if ((d=(*i)->getShareDevice()) != (dev_t)0) {
1440 (*i)->getVolInfo(&vol_list[n]);
1441 snprintf(vol_list[n].blk_dev, sizeof(vol_list[n].blk_dev),
1442 "/dev/block/vold/%d:%d",MAJOR(d), MINOR(d));
1443 n++;
1444 }
1445 }
1446
1447 return 0;
1448}
1449
Ken Sumrall0b8b5972011-08-31 16:14:23 -07001450int VolumeManager::unmountVolume(const char *label, bool force, bool revert) {
San Mehat49e2bce2009-10-12 16:29:01 -07001451 Volume *v = lookupVolume(label);
1452
1453 if (!v) {
1454 errno = ENOENT;
1455 return -1;
1456 }
1457
San Mehata2677e42009-12-13 10:40:18 -08001458 if (v->getState() == Volume::State_NoMedia) {
1459 errno = ENODEV;
1460 return -1;
1461 }
1462
San Mehat49e2bce2009-10-12 16:29:01 -07001463 if (v->getState() != Volume::State_Mounted) {
San Mehat97ac40e2010-03-24 10:24:19 -07001464 SLOGW("Attempt to unmount volume which isn't mounted (%d)\n",
San Mehata2677e42009-12-13 10:40:18 -08001465 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -07001466 errno = EBUSY;
Ken Sumrall319b1042011-06-14 14:01:55 -07001467 return UNMOUNT_NOT_MOUNTED_ERR;
San Mehat49e2bce2009-10-12 16:29:01 -07001468 }
1469
San Mehat1a06eda2010-04-15 12:58:50 -07001470 cleanupAsec(v, force);
San Mehat88705162010-01-15 09:26:28 -08001471
Ken Sumrall0b8b5972011-08-31 16:14:23 -07001472 return v->unmountVol(force, revert);
San Mehat49e2bce2009-10-12 16:29:01 -07001473}
1474
Ken Sumrall425524d2012-06-14 20:55:28 -07001475extern "C" int vold_unmountAllAsecs(void) {
1476 int rc;
1477
1478 VolumeManager *vm = VolumeManager::Instance();
1479 rc = vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_EXT);
1480 if (vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_INT)) {
1481 rc = -1;
1482 }
1483 return rc;
1484}
1485
1486#define ID_BUF_LEN 256
1487#define ASEC_SUFFIX ".asec"
1488#define ASEC_SUFFIX_LEN (sizeof(ASEC_SUFFIX) - 1)
1489int VolumeManager::unmountAllAsecsInDir(const char *directory) {
1490 DIR *d = opendir(directory);
1491 int rc = 0;
1492
1493 if (!d) {
1494 SLOGE("Could not open asec dir %s", directory);
1495 return -1;
1496 }
1497
1498 size_t dirent_len = offsetof(struct dirent, d_name) +
1499 pathconf(directory, _PC_NAME_MAX) + 1;
1500
1501 struct dirent *dent = (struct dirent *) malloc(dirent_len);
1502 if (dent == NULL) {
1503 SLOGE("Failed to allocate memory for asec dir");
1504 return -1;
1505 }
1506
1507 struct dirent *result;
1508 while (!readdir_r(d, dent, &result) && result != NULL) {
1509 if (dent->d_name[0] == '.')
1510 continue;
1511 if (dent->d_type != DT_REG)
1512 continue;
1513 size_t name_len = strlen(dent->d_name);
1514 if (name_len > 5 && name_len < (ID_BUF_LEN + ASEC_SUFFIX_LEN - 1) &&
1515 !strcmp(&dent->d_name[name_len - 5], ASEC_SUFFIX)) {
1516 char id[ID_BUF_LEN];
1517 strlcpy(id, dent->d_name, name_len - 4);
1518 if (unmountAsec(id, true)) {
1519 /* Register the error, but try to unmount more asecs */
1520 rc = -1;
1521 }
1522 }
1523 }
1524 closedir(d);
1525
1526 free(dent);
1527
1528 return rc;
1529}
1530
San Mehata2677e42009-12-13 10:40:18 -08001531/*
1532 * Looks up a volume by it's label or mount-point
1533 */
San Mehat49e2bce2009-10-12 16:29:01 -07001534Volume *VolumeManager::lookupVolume(const char *label) {
1535 VolumeCollection::iterator i;
1536
1537 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -08001538 if (label[0] == '/') {
1539 if (!strcmp(label, (*i)->getMountpoint()))
1540 return (*i);
1541 } else {
1542 if (!strcmp(label, (*i)->getLabel()))
1543 return (*i);
1544 }
San Mehat49e2bce2009-10-12 16:29:01 -07001545 }
1546 return NULL;
1547}
San Mehata19b2502010-01-06 10:33:53 -08001548
1549bool VolumeManager::isMountpointMounted(const char *mp)
1550{
1551 char device[256];
1552 char mount_path[256];
1553 char rest[256];
1554 FILE *fp;
1555 char line[1024];
1556
1557 if (!(fp = fopen("/proc/mounts", "r"))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001558 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001559 return false;
1560 }
1561
1562 while(fgets(line, sizeof(line), fp)) {
1563 line[strlen(line)-1] = '\0';
1564 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1565 if (!strcmp(mount_path, mp)) {
1566 fclose(fp);
1567 return true;
1568 }
San Mehata19b2502010-01-06 10:33:53 -08001569 }
1570
1571 fclose(fp);
1572 return false;
1573}
1574
San Mehat1a06eda2010-04-15 12:58:50 -07001575int VolumeManager::cleanupAsec(Volume *v, bool force) {
Kenny Rooteacf7e02012-08-09 11:28:37 -07001576 int rc = unmountAllAsecsInDir(Volume::SEC_ASECDIR_EXT);
1577
1578 AsecIdCollection toUnmount;
1579 // Find the remaining OBB files that are on external storage.
1580 for (AsecIdCollection::iterator it = mActiveContainers->begin(); it != mActiveContainers->end();
1581 ++it) {
Kenny Rootcbacf782010-09-24 15:11:48 -07001582 ContainerData* cd = *it;
Kenny Rooteacf7e02012-08-09 11:28:37 -07001583
Kenny Rootcbacf782010-09-24 15:11:48 -07001584 if (cd->type == ASEC) {
Kenny Rooteacf7e02012-08-09 11:28:37 -07001585 // nothing
Kenny Rootcbacf782010-09-24 15:11:48 -07001586 } else if (cd->type == OBB) {
Kenny Rooteacf7e02012-08-09 11:28:37 -07001587 if (v == getVolumeForFile(cd->id)) {
1588 toUnmount.push_back(cd);
Kenny Rootcbacf782010-09-24 15:11:48 -07001589 }
1590 } else {
1591 SLOGE("Unknown container type %d!", cd->type);
San Mehat1a06eda2010-04-15 12:58:50 -07001592 }
1593 }
Kenny Rooteacf7e02012-08-09 11:28:37 -07001594
1595 for (AsecIdCollection::iterator it = toUnmount.begin(); it != toUnmount.end(); ++it) {
1596 ContainerData *cd = *it;
1597 SLOGI("Unmounting ASEC %s (dependant on %s)", cd->id, v->getMountpoint());
1598 if (unmountObb(cd->id, force)) {
1599 SLOGE("Failed to unmount OBB %s (%s)", cd->id, strerror(errno));
1600 rc = -1;
1601 }
1602 }
1603
1604 return rc;
1605
San Mehat1a06eda2010-04-15 12:58:50 -07001606}
1607