blob: 3c2dd3383535215f53242d3716aba24cea9ee99c [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
Jeff Sharkey71ebe152013-09-17 17:24:38 -070035#include <cutils/fs.h>
San Mehatf1b736b2009-10-10 17:22:08 -070036#include <cutils/log.h>
37
Robert Craigb9e3ba52014-02-04 10:53:00 -050038#include <selinux/android.h>
39
San Mehatfd7f5872009-10-12 11:32:47 -070040#include <sysutils/NetlinkEvent.h>
41
Kenny Root344ca102012-04-03 17:23:01 -070042#include <private/android_filesystem_config.h>
43
San Mehatf1b736b2009-10-10 17:22:08 -070044#include "VolumeManager.h"
San Mehatae10b912009-10-12 14:57:05 -070045#include "DirectVolume.h"
San Mehata2677e42009-12-13 10:40:18 -080046#include "ResponseCode.h"
San Mehata19b2502010-01-06 10:33:53 -080047#include "Loop.h"
Kenny Root344ca102012-04-03 17:23:01 -070048#include "Ext4.h"
San Mehata19b2502010-01-06 10:33:53 -080049#include "Fat.h"
San Mehatb78a32c2010-01-10 13:02:12 -080050#include "Devmapper.h"
San Mehat586536c2010-02-16 17:12:00 -080051#include "Process.h"
San Mehatfcf24fe2010-03-03 12:37:32 -080052#include "Asec.h"
Ken Sumrall29d8da82011-05-18 17:20:07 -070053#include "cryptfs.h"
San Mehat23969932010-01-09 07:08:06 -080054
Mike Lockwood97f2fc12011-06-07 10:51:38 -070055#define MASS_STORAGE_FILE_PATH "/sys/class/android_usb/android0/f_mass_storage/lun/file"
56
San Mehatf1b736b2009-10-10 17:22:08 -070057VolumeManager *VolumeManager::sInstance = NULL;
58
59VolumeManager *VolumeManager::Instance() {
60 if (!sInstance)
61 sInstance = new VolumeManager();
62 return sInstance;
63}
64
65VolumeManager::VolumeManager() {
San Mehatd9a4e352010-03-12 13:32:47 -080066 mDebug = false;
San Mehatf1b736b2009-10-10 17:22:08 -070067 mVolumes = new VolumeCollection();
San Mehat88705162010-01-15 09:26:28 -080068 mActiveContainers = new AsecIdCollection();
San Mehatf1b736b2009-10-10 17:22:08 -070069 mBroadcaster = NULL;
Mike Lockwooda28056b2010-10-28 15:21:24 -040070 mUmsSharingCount = 0;
71 mSavedDirtyRatio = -1;
72 // set dirty ratio to 0 when UMS is active
73 mUmsDirtyRatio = 0;
Ken Sumrall3b170052011-07-11 15:38:57 -070074 mVolManagerDisabled = 0;
San Mehatf1b736b2009-10-10 17:22:08 -070075}
76
77VolumeManager::~VolumeManager() {
San Mehat88705162010-01-15 09:26:28 -080078 delete mVolumes;
79 delete mActiveContainers;
San Mehatf1b736b2009-10-10 17:22:08 -070080}
81
Kenny Root7b18a7b2010-03-15 13:13:41 -070082char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -070083 static const char* digits = "0123456789abcdef";
84
Kenny Root7b18a7b2010-03-15 13:13:41 -070085 unsigned char sig[MD5_DIGEST_LENGTH];
86
Kenny Rootacc9e7d2010-06-18 19:06:50 -070087 if (buffer == NULL) {
88 SLOGE("Destination buffer is NULL");
89 errno = ESPIPE;
90 return NULL;
91 } else if (id == NULL) {
92 SLOGE("Source buffer is NULL");
93 errno = ESPIPE;
94 return NULL;
95 } else if (len < MD5_ASCII_LENGTH_PLUS_NULL) {
96 SLOGE("Target hash buffer size < %d bytes (%d)",
97 MD5_ASCII_LENGTH_PLUS_NULL, len);
San Mehatd9a4e352010-03-12 13:32:47 -080098 errno = ESPIPE;
99 return NULL;
100 }
Kenny Root7b18a7b2010-03-15 13:13:41 -0700101
102 MD5(reinterpret_cast<const unsigned char*>(id), strlen(id), sig);
San Mehatd9a4e352010-03-12 13:32:47 -0800103
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700104 char *p = buffer;
Kenny Root7b18a7b2010-03-15 13:13:41 -0700105 for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700106 *p++ = digits[sig[i] >> 4];
107 *p++ = digits[sig[i] & 0x0F];
San Mehatd9a4e352010-03-12 13:32:47 -0800108 }
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700109 *p = '\0';
San Mehatd9a4e352010-03-12 13:32:47 -0800110
111 return buffer;
112}
113
114void VolumeManager::setDebug(bool enable) {
115 mDebug = enable;
116 VolumeCollection::iterator it;
117 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
118 (*it)->setDebug(enable);
119 }
120}
121
San Mehatf1b736b2009-10-10 17:22:08 -0700122int VolumeManager::start() {
123 return 0;
124}
125
126int VolumeManager::stop() {
127 return 0;
128}
129
130int VolumeManager::addVolume(Volume *v) {
131 mVolumes->push_back(v);
132 return 0;
133}
134
San Mehatfd7f5872009-10-12 11:32:47 -0700135void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
136 const char *devpath = evt->findParam("DEVPATH");
San Mehatf1b736b2009-10-10 17:22:08 -0700137
San Mehatfd7f5872009-10-12 11:32:47 -0700138 /* Lookup a volume to handle this device */
San Mehatf1b736b2009-10-10 17:22:08 -0700139 VolumeCollection::iterator it;
140 bool hit = false;
141 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
San Mehatfd7f5872009-10-12 11:32:47 -0700142 if (!(*it)->handleBlockEvent(evt)) {
San Mehata2677e42009-12-13 10:40:18 -0800143#ifdef NETLINK_DEBUG
San Mehat97ac40e2010-03-24 10:24:19 -0700144 SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
San Mehata2677e42009-12-13 10:40:18 -0800145#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700146 hit = true;
San Mehatf1b736b2009-10-10 17:22:08 -0700147 break;
148 }
149 }
150
151 if (!hit) {
San Mehata2677e42009-12-13 10:40:18 -0800152#ifdef NETLINK_DEBUG
San Mehat97ac40e2010-03-24 10:24:19 -0700153 SLOGW("No volumes handled block event for '%s'", devpath);
San Mehata2677e42009-12-13 10:40:18 -0800154#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700155 }
156}
157
San Mehatf1b736b2009-10-10 17:22:08 -0700158int VolumeManager::listVolumes(SocketClient *cli) {
159 VolumeCollection::iterator i;
160
161 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
162 char *buffer;
163 asprintf(&buffer, "%s %s %d",
Jeff Sharkeyba6ae8d2013-07-15 18:14:25 -0700164 (*i)->getLabel(), (*i)->getFuseMountpoint(),
San Mehatf1b736b2009-10-10 17:22:08 -0700165 (*i)->getState());
San Mehata2677e42009-12-13 10:40:18 -0800166 cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
San Mehatf1b736b2009-10-10 17:22:08 -0700167 free(buffer);
168 }
San Mehata2677e42009-12-13 10:40:18 -0800169 cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
San Mehatf1b736b2009-10-10 17:22:08 -0700170 return 0;
171}
San Mehat49e2bce2009-10-12 16:29:01 -0700172
Ken Sumrall9caab762013-06-11 19:10:20 -0700173int VolumeManager::formatVolume(const char *label, bool wipe) {
San Mehata2677e42009-12-13 10:40:18 -0800174 Volume *v = lookupVolume(label);
175
176 if (!v) {
177 errno = ENOENT;
178 return -1;
179 }
180
Ken Sumrall3b170052011-07-11 15:38:57 -0700181 if (mVolManagerDisabled) {
182 errno = EBUSY;
183 return -1;
184 }
185
Ken Sumrall9caab762013-06-11 19:10:20 -0700186 return v->formatVol(wipe);
San Mehata2677e42009-12-13 10:40:18 -0800187}
188
Kenny Root508c0e12010-07-12 09:59:49 -0700189int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) {
190 char idHash[33];
191 if (!asecHash(sourceFile, idHash, sizeof(idHash))) {
192 SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno));
193 return -1;
194 }
195
196 memset(mountPath, 0, mountPathLen);
rpcraigd1c226f2012-10-09 06:58:16 -0400197 int written = snprintf(mountPath, mountPathLen, "%s/%s", Volume::LOOPDIR, idHash);
198 if ((written < 0) || (written >= mountPathLen)) {
199 errno = EINVAL;
200 return -1;
201 }
Kenny Root508c0e12010-07-12 09:59:49 -0700202
203 if (access(mountPath, F_OK)) {
204 errno = ENOENT;
205 return -1;
206 }
207
208 return 0;
209}
210
San Mehata19b2502010-01-06 10:33:53 -0800211int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
San Mehat88ac2c02010-03-23 11:15:58 -0700212 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700213
214 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
215 SLOGE("Couldn't find ASEC %s", id);
216 return -1;
217 }
San Mehat88ac2c02010-03-23 11:15:58 -0700218
219 memset(buffer, 0, maxlen);
220 if (access(asecFileName, F_OK)) {
221 errno = ENOENT;
222 return -1;
223 }
San Mehata19b2502010-01-06 10:33:53 -0800224
rpcraigd1c226f2012-10-09 06:58:16 -0400225 int written = snprintf(buffer, maxlen, "%s/%s", Volume::ASECDIR, id);
226 if ((written < 0) || (written >= maxlen)) {
227 SLOGE("getAsecMountPath failed for %s: couldn't construct path in buffer", id);
228 errno = EINVAL;
229 return -1;
230 }
231
San Mehata19b2502010-01-06 10:33:53 -0800232 return 0;
233}
234
Dianne Hackborn736910c2011-06-27 13:37:07 -0700235int VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxlen) {
236 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700237
238 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
239 SLOGE("Couldn't find ASEC %s", id);
240 return -1;
241 }
Dianne Hackborn736910c2011-06-27 13:37:07 -0700242
243 memset(buffer, 0, maxlen);
244 if (access(asecFileName, F_OK)) {
245 errno = ENOENT;
246 return -1;
247 }
248
rpcraigd1c226f2012-10-09 06:58:16 -0400249 int written = snprintf(buffer, maxlen, "%s", asecFileName);
250 if ((written < 0) || (written >= maxlen)) {
251 errno = EINVAL;
252 return -1;
253 }
254
Dianne Hackborn736910c2011-06-27 13:37:07 -0700255 return 0;
256}
257
Kenny Root344ca102012-04-03 17:23:01 -0700258int VolumeManager::createAsec(const char *id, unsigned int numSectors, const char *fstype,
259 const char *key, const int ownerUid, bool isExternal) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800260 struct asec_superblock sb;
261 memset(&sb, 0, sizeof(sb));
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
rpcraigd1c226f2012-10-09 06:58:16 -0400302 int written = snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", asecDir, id);
303 if ((written < 0) || (size_t(written) >= sizeof(asecFileName))) {
304 errno = EINVAL;
305 return -1;
306 }
San Mehata19b2502010-01-06 10:33:53 -0800307
308 if (!access(asecFileName, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700309 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
Kenny Root344ca102012-04-03 17:23:01 -0700310 asecFileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800311 errno = EADDRINUSE;
312 return -1;
313 }
314
San Mehatfcf24fe2010-03-03 12:37:32 -0800315 /*
316 * Add some headroom
317 */
318 unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
319 unsigned numImgSectors = numSectors + fatSize + 2;
320
321 if (numImgSectors % 63) {
322 numImgSectors += (63 - (numImgSectors % 63));
323 }
324
325 // Add +1 for our superblock which is at the end
326 if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700327 SLOGE("ASEC image file creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800328 return -1;
329 }
330
San Mehatd9a4e352010-03-12 13:32:47 -0800331 char idHash[33];
332 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700333 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800334 unlink(asecFileName);
335 return -1;
336 }
337
San Mehata19b2502010-01-06 10:33:53 -0800338 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800339 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700340 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800341 unlink(asecFileName);
342 return -1;
343 }
344
San Mehatb78a32c2010-01-10 13:02:12 -0800345 char dmDevice[255];
346 bool cleanupDm = false;
San Mehata19b2502010-01-06 10:33:53 -0800347
San Mehatb78a32c2010-01-10 13:02:12 -0800348 if (strcmp(key, "none")) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800349 // XXX: This is all we support for now
350 sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
San Mehatd9a4e352010-03-12 13:32:47 -0800351 if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
San Mehatb78a32c2010-01-10 13:02:12 -0800352 sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700353 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800354 Loop::destroyByDevice(loopDevice);
355 unlink(asecFileName);
356 return -1;
357 }
358 cleanupDm = true;
359 } else {
San Mehatfcf24fe2010-03-03 12:37:32 -0800360 sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
San Mehatb78a32c2010-01-10 13:02:12 -0800361 strcpy(dmDevice, loopDevice);
362 }
363
San Mehatfcf24fe2010-03-03 12:37:32 -0800364 /*
365 * Drop down the superblock at the end of the file
366 */
367
368 int sbfd = open(loopDevice, O_RDWR);
369 if (sbfd < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700370 SLOGE("Failed to open new DM device for superblock write (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800371 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800372 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800373 }
374 Loop::destroyByDevice(loopDevice);
375 unlink(asecFileName);
376 return -1;
377 }
378
379 if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
380 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700381 SLOGE("Failed to lseek for superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800382 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800383 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800384 }
385 Loop::destroyByDevice(loopDevice);
386 unlink(asecFileName);
387 return -1;
388 }
389
390 if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) {
391 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700392 SLOGE("Failed to write superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800393 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800394 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800395 }
396 Loop::destroyByDevice(loopDevice);
397 unlink(asecFileName);
398 return -1;
399 }
400 close(sbfd);
401
Kenny Root344ca102012-04-03 17:23:01 -0700402 if (wantFilesystem) {
403 int formatStatus;
rpcraiga54e13a2012-09-21 14:17:08 -0400404 char mountPoint[255];
405
rpcraigd1c226f2012-10-09 06:58:16 -0400406 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
407 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
408 SLOGE("ASEC fs format failed: couldn't construct mountPoint");
409 if (cleanupDm) {
410 Devmapper::destroy(idHash);
411 }
412 Loop::destroyByDevice(loopDevice);
413 unlink(asecFileName);
414 return -1;
415 }
rpcraiga54e13a2012-09-21 14:17:08 -0400416
Kenny Root344ca102012-04-03 17:23:01 -0700417 if (usingExt4) {
rpcraiga54e13a2012-09-21 14:17:08 -0400418 formatStatus = Ext4::format(dmDevice, mountPoint);
Kenny Root344ca102012-04-03 17:23:01 -0700419 } else {
Ken Sumrall9caab762013-06-11 19:10:20 -0700420 formatStatus = Fat::format(dmDevice, numImgSectors, 0);
San Mehatb78a32c2010-01-10 13:02:12 -0800421 }
San Mehata19b2502010-01-06 10:33:53 -0800422
Kenny Root344ca102012-04-03 17:23:01 -0700423 if (formatStatus < 0) {
424 SLOGE("ASEC fs format failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800425 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800426 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800427 }
San Mehateb13a902010-01-07 12:12:50 -0800428 Loop::destroyByDevice(loopDevice);
429 unlink(asecFileName);
430 return -1;
431 }
Kenny Root344ca102012-04-03 17:23:01 -0700432
Kenny Root344ca102012-04-03 17:23:01 -0700433 if (mkdir(mountPoint, 0000)) {
San Mehata1091cb2010-02-28 20:17:20 -0800434 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -0700435 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800436 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800437 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800438 }
439 Loop::destroyByDevice(loopDevice);
440 unlink(asecFileName);
441 return -1;
442 }
San Mehatb78a32c2010-01-10 13:02:12 -0800443 }
San Mehata1091cb2010-02-28 20:17:20 -0800444
Kenny Root344ca102012-04-03 17:23:01 -0700445 int mountStatus;
446 if (usingExt4) {
447 mountStatus = Ext4::doMount(dmDevice, mountPoint, false, false, false);
448 } else {
449 mountStatus = Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid, 0, 0000,
450 false);
451 }
452
453 if (mountStatus) {
San Mehat97ac40e2010-03-24 10:24:19 -0700454 SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800455 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800456 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800457 }
458 Loop::destroyByDevice(loopDevice);
459 unlink(asecFileName);
460 return -1;
461 }
Kenny Root344ca102012-04-03 17:23:01 -0700462
463 if (usingExt4) {
464 int dirfd = open(mountPoint, O_DIRECTORY);
465 if (dirfd >= 0) {
466 if (fchown(dirfd, ownerUid, AID_SYSTEM)
467 || fchmod(dirfd, S_IRUSR | S_IWUSR | S_IXUSR | S_ISGID | S_IRGRP | S_IXGRP)) {
468 SLOGI("Cannot chown/chmod new ASEC mount point %s", mountPoint);
469 }
470 close(dirfd);
471 }
472 }
San Mehata1091cb2010-02-28 20:17:20 -0800473 } else {
San Mehat97ac40e2010-03-24 10:24:19 -0700474 SLOGI("Created raw secure container %s (no filesystem)", id);
San Mehata19b2502010-01-06 10:33:53 -0800475 }
San Mehat88705162010-01-15 09:26:28 -0800476
Kenny Rootcbacf782010-09-24 15:11:48 -0700477 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehata19b2502010-01-06 10:33:53 -0800478 return 0;
479}
480
481int VolumeManager::finalizeAsec(const char *id) {
482 char asecFileName[255];
483 char loopDevice[255];
484 char mountPoint[255];
485
Kenny Root344ca102012-04-03 17:23:01 -0700486 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
487 SLOGE("Couldn't find ASEC %s", id);
488 return -1;
489 }
San Mehata19b2502010-01-06 10:33:53 -0800490
San Mehatd9a4e352010-03-12 13:32:47 -0800491 char idHash[33];
492 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700493 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800494 return -1;
495 }
496
497 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700498 SLOGE("Unable to finalize %s (%s)", id, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800499 return -1;
500 }
501
Kenny Root344ca102012-04-03 17:23:01 -0700502 unsigned int nr_sec = 0;
503 struct asec_superblock sb;
504
505 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
506 return -1;
507 }
508
rpcraigd1c226f2012-10-09 06:58:16 -0400509 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
510 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
511 SLOGE("ASEC finalize failed: couldn't construct mountPoint");
512 return -1;
513 }
Kenny Root344ca102012-04-03 17:23:01 -0700514
515 int result = 0;
516 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
517 result = Ext4::doMount(loopDevice, mountPoint, true, true, true);
518 } else {
519 result = Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false);
520 }
521
522 if (result) {
San Mehat97ac40e2010-03-24 10:24:19 -0700523 SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800524 return -1;
525 }
526
San Mehatd9a4e352010-03-12 13:32:47 -0800527 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700528 SLOGD("ASEC %s finalized", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800529 }
San Mehata19b2502010-01-06 10:33:53 -0800530 return 0;
531}
532
Kenny Root344ca102012-04-03 17:23:01 -0700533int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* filename) {
534 char asecFileName[255];
535 char loopDevice[255];
536 char mountPoint[255];
537
538 if (gid < AID_APP) {
539 SLOGE("Group ID is not in application range");
540 return -1;
541 }
542
543 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
544 SLOGE("Couldn't find ASEC %s", id);
545 return -1;
546 }
547
548 char idHash[33];
549 if (!asecHash(id, idHash, sizeof(idHash))) {
550 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
551 return -1;
552 }
553
554 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
555 SLOGE("Unable fix permissions during lookup on %s (%s)", id, strerror(errno));
556 return -1;
557 }
558
559 unsigned int nr_sec = 0;
560 struct asec_superblock sb;
561
562 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
563 return -1;
564 }
565
rpcraigd1c226f2012-10-09 06:58:16 -0400566 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
567 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
568 SLOGE("Unable remount to fix permissions for %s: couldn't construct mountpoint", id);
569 return -1;
570 }
Kenny Root344ca102012-04-03 17:23:01 -0700571
572 int result = 0;
573 if ((sb.c_opts & ASEC_SB_C_OPTS_EXT4) == 0) {
574 return 0;
575 }
576
577 int ret = Ext4::doMount(loopDevice, mountPoint,
578 false /* read-only */,
579 true /* remount */,
580 false /* executable */);
581 if (ret) {
582 SLOGE("Unable remount to fix permissions for %s (%s)", id, strerror(errno));
583 return -1;
584 }
585
586 char *paths[] = { mountPoint, NULL };
587
588 FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL);
589 if (fts) {
590 // Traverse the entire hierarchy and chown to system UID.
591 for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
592 // We don't care about the lost+found directory.
593 if (!strcmp(ftsent->fts_name, "lost+found")) {
594 continue;
595 }
596
597 /*
598 * There can only be one file marked as private right now.
599 * This should be more robust, but it satisfies the requirements
600 * we have for right now.
601 */
602 const bool privateFile = !strcmp(ftsent->fts_name, filename);
603
604 int fd = open(ftsent->fts_accpath, O_NOFOLLOW);
605 if (fd < 0) {
606 SLOGE("Couldn't open file %s: %s", ftsent->fts_accpath, strerror(errno));
607 result = -1;
608 continue;
609 }
610
611 result |= fchown(fd, AID_SYSTEM, privateFile? gid : AID_SYSTEM);
612
613 if (ftsent->fts_info & FTS_D) {
Kenny Root1a673c82012-05-10 16:45:29 -0700614 result |= fchmod(fd, 0755);
Kenny Root348c8ab2012-05-10 15:39:53 -0700615 } else if (ftsent->fts_info & FTS_F) {
Kenny Root344ca102012-04-03 17:23:01 -0700616 result |= fchmod(fd, privateFile ? 0640 : 0644);
617 }
Robert Craigb9e3ba52014-02-04 10:53:00 -0500618
619 if (selinux_android_restorecon(ftsent->fts_path) < 0) {
620 SLOGE("restorecon failed for %s: %s\n", ftsent->fts_path, strerror(errno));
621 result |= -1;
622 }
623
Kenny Root344ca102012-04-03 17:23:01 -0700624 close(fd);
625 }
626 fts_close(fts);
627
628 // Finally make the directory readable by everyone.
629 int dirfd = open(mountPoint, O_DIRECTORY);
630 if (dirfd < 0 || fchmod(dirfd, 0755)) {
631 SLOGE("Couldn't change owner of existing directory %s: %s", mountPoint, strerror(errno));
632 result |= -1;
633 }
634 close(dirfd);
635 } else {
636 result |= -1;
637 }
638
639 result |= Ext4::doMount(loopDevice, mountPoint,
640 true /* read-only */,
641 true /* remount */,
642 true /* execute */);
643
644 if (result) {
645 SLOGE("ASEC fix permissions failed (%s)", strerror(errno));
646 return -1;
647 }
648
649 if (mDebug) {
650 SLOGD("ASEC %s permissions fixed", id);
651 }
652 return 0;
653}
654
San Mehat048b0802010-01-23 08:17:06 -0800655int VolumeManager::renameAsec(const char *id1, const char *id2) {
Kenny Root344ca102012-04-03 17:23:01 -0700656 char asecFilename1[255];
San Mehat048b0802010-01-23 08:17:06 -0800657 char *asecFilename2;
658 char mountPoint[255];
659
Kenny Root344ca102012-04-03 17:23:01 -0700660 const char *dir;
661
662 if (findAsec(id1, asecFilename1, sizeof(asecFilename1), &dir)) {
663 SLOGE("Couldn't find ASEC %s", id1);
664 return -1;
665 }
666
667 asprintf(&asecFilename2, "%s/%s.asec", dir, id2);
San Mehat048b0802010-01-23 08:17:06 -0800668
rpcraigd1c226f2012-10-09 06:58:16 -0400669 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
670 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
671 SLOGE("Rename failed: couldn't construct mountpoint");
672 goto out_err;
673 }
674
San Mehat048b0802010-01-23 08:17:06 -0800675 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700676 SLOGW("Rename attempt when src mounted");
San Mehat048b0802010-01-23 08:17:06 -0800677 errno = EBUSY;
678 goto out_err;
679 }
680
rpcraigd1c226f2012-10-09 06:58:16 -0400681 written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2);
682 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
683 SLOGE("Rename failed: couldn't construct mountpoint2");
684 goto out_err;
685 }
686
San Mehat96956ed2010-02-24 08:42:51 -0800687 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700688 SLOGW("Rename attempt when dst mounted");
San Mehat96956ed2010-02-24 08:42:51 -0800689 errno = EBUSY;
690 goto out_err;
691 }
692
San Mehat048b0802010-01-23 08:17:06 -0800693 if (!access(asecFilename2, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700694 SLOGE("Rename attempt when dst exists");
San Mehat048b0802010-01-23 08:17:06 -0800695 errno = EADDRINUSE;
696 goto out_err;
697 }
698
699 if (rename(asecFilename1, asecFilename2)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700700 SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
San Mehat048b0802010-01-23 08:17:06 -0800701 goto out_err;
702 }
703
San Mehat048b0802010-01-23 08:17:06 -0800704 free(asecFilename2);
705 return 0;
706
707out_err:
San Mehat048b0802010-01-23 08:17:06 -0800708 free(asecFilename2);
709 return -1;
710}
711
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700712#define UNMOUNT_RETRIES 5
713#define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
San Mehat4ba89482010-02-18 09:00:18 -0800714int VolumeManager::unmountAsec(const char *id, bool force) {
San Mehata19b2502010-01-06 10:33:53 -0800715 char asecFileName[255];
716 char mountPoint[255];
717
Kenny Root344ca102012-04-03 17:23:01 -0700718 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
719 SLOGE("Couldn't find ASEC %s", id);
720 return -1;
721 }
722
rpcraigd1c226f2012-10-09 06:58:16 -0400723 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
724 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
725 SLOGE("ASEC unmount failed for %s: couldn't construct mountpoint", id);
726 return -1;
727 }
San Mehata19b2502010-01-06 10:33:53 -0800728
San Mehatd9a4e352010-03-12 13:32:47 -0800729 char idHash[33];
730 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700731 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800732 return -1;
733 }
734
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700735 return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
736}
737
Kenny Root508c0e12010-07-12 09:59:49 -0700738int VolumeManager::unmountObb(const char *fileName, bool force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700739 char mountPoint[255];
740
741 char idHash[33];
742 if (!asecHash(fileName, idHash, sizeof(idHash))) {
743 SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
744 return -1;
745 }
746
rpcraigd1c226f2012-10-09 06:58:16 -0400747 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
748 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
749 SLOGE("OBB unmount failed for %s: couldn't construct mountpoint", fileName);
750 return -1;
751 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700752
753 return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
754}
755
756int VolumeManager::unmountLoopImage(const char *id, const char *idHash,
757 const char *fileName, const char *mountPoint, bool force) {
San Mehat0586d542010-01-12 15:38:59 -0800758 if (!isMountpointMounted(mountPoint)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700759 SLOGE("Unmount request for %s when not mounted", id);
Kenny Root918e5f92010-09-30 18:00:52 -0700760 errno = ENOENT;
San Mehatb78a32c2010-01-10 13:02:12 -0800761 return -1;
762 }
San Mehat23969932010-01-09 07:08:06 -0800763
San Mehatb78a32c2010-01-10 13:02:12 -0800764 int i, rc;
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700765 for (i = 1; i <= UNMOUNT_RETRIES; i++) {
San Mehatb78a32c2010-01-10 13:02:12 -0800766 rc = umount(mountPoint);
767 if (!rc) {
768 break;
San Mehata19b2502010-01-06 10:33:53 -0800769 }
San Mehatb78a32c2010-01-10 13:02:12 -0800770 if (rc && (errno == EINVAL || errno == ENOENT)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700771 SLOGI("Container %s unmounted OK", id);
San Mehatb78a32c2010-01-10 13:02:12 -0800772 rc = 0;
773 break;
San Mehata19b2502010-01-06 10:33:53 -0800774 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700775 SLOGW("%s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -0800776 id, i, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800777
San Mehat4ba89482010-02-18 09:00:18 -0800778 int action = 0; // default is to just complain
779
780 if (force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700781 if (i > (UNMOUNT_RETRIES - 2))
San Mehat4ba89482010-02-18 09:00:18 -0800782 action = 2; // SIGKILL
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700783 else if (i > (UNMOUNT_RETRIES - 3))
San Mehat4ba89482010-02-18 09:00:18 -0800784 action = 1; // SIGHUP
785 }
San Mehat8c940ef2010-02-13 14:19:53 -0800786
San Mehat586536c2010-02-16 17:12:00 -0800787 Process::killProcessesWithOpenFiles(mountPoint, action);
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700788 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehatb78a32c2010-01-10 13:02:12 -0800789 }
790
791 if (rc) {
San Mehat4ba89482010-02-18 09:00:18 -0800792 errno = EBUSY;
San Mehat97ac40e2010-03-24 10:24:19 -0700793 SLOGE("Failed to unmount container %s (%s)", id, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800794 return -1;
795 }
796
San Mehat12f4b892010-02-24 11:43:22 -0800797 int retries = 10;
798
799 while(retries--) {
800 if (!rmdir(mountPoint)) {
801 break;
802 }
803
San Mehat97ac40e2010-03-24 10:24:19 -0700804 SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700805 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehat12f4b892010-02-24 11:43:22 -0800806 }
807
808 if (!retries) {
San Mehat97ac40e2010-03-24 10:24:19 -0700809 SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
San Mehatf5c61982010-02-03 11:04:46 -0800810 }
San Mehat88705162010-01-15 09:26:28 -0800811
San Mehatd9a4e352010-03-12 13:32:47 -0800812 if (Devmapper::destroy(idHash) && errno != ENXIO) {
San Mehat97ac40e2010-03-24 10:24:19 -0700813 SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800814 }
815
816 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800817 if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800818 Loop::destroyByDevice(loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800819 } else {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700820 SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800821 }
San Mehat88705162010-01-15 09:26:28 -0800822
823 AsecIdCollection::iterator it;
824 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
Kenny Rootcbacf782010-09-24 15:11:48 -0700825 ContainerData* cd = *it;
826 if (!strcmp(cd->id, id)) {
San Mehat88705162010-01-15 09:26:28 -0800827 free(*it);
828 mActiveContainers->erase(it);
829 break;
830 }
831 }
832 if (it == mActiveContainers->end()) {
San Mehat97ac40e2010-03-24 10:24:19 -0700833 SLOGW("mActiveContainers is inconsistent!");
San Mehat88705162010-01-15 09:26:28 -0800834 }
San Mehatb78a32c2010-01-10 13:02:12 -0800835 return 0;
836}
837
San Mehat4ba89482010-02-18 09:00:18 -0800838int VolumeManager::destroyAsec(const char *id, bool force) {
San Mehatb78a32c2010-01-10 13:02:12 -0800839 char asecFileName[255];
840 char mountPoint[255];
841
Kenny Root344ca102012-04-03 17:23:01 -0700842 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
843 SLOGE("Couldn't find ASEC %s", id);
844 return -1;
845 }
846
rpcraigd1c226f2012-10-09 06:58:16 -0400847 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
848 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
849 SLOGE("ASEC destroy failed for %s: couldn't construct mountpoint", id);
850 return -1;
851 }
San Mehatb78a32c2010-01-10 13:02:12 -0800852
San Mehat0586d542010-01-12 15:38:59 -0800853 if (isMountpointMounted(mountPoint)) {
San Mehatd9a4e352010-03-12 13:32:47 -0800854 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700855 SLOGD("Unmounting container before destroy");
San Mehatd9a4e352010-03-12 13:32:47 -0800856 }
San Mehat4ba89482010-02-18 09:00:18 -0800857 if (unmountAsec(id, force)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700858 SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800859 return -1;
860 }
861 }
San Mehata19b2502010-01-06 10:33:53 -0800862
San Mehat0586d542010-01-12 15:38:59 -0800863 if (unlink(asecFileName)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700864 SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800865 return -1;
866 }
San Mehata19b2502010-01-06 10:33:53 -0800867
San Mehatd9a4e352010-03-12 13:32:47 -0800868 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700869 SLOGD("ASEC %s destroyed", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800870 }
San Mehata19b2502010-01-06 10:33:53 -0800871 return 0;
872}
873
Kenny Root344ca102012-04-03 17:23:01 -0700874bool VolumeManager::isAsecInDirectory(const char *dir, const char *asecName) const {
875 int dirfd = open(dir, O_DIRECTORY);
876 if (dirfd < 0) {
877 SLOGE("Couldn't open internal ASEC dir (%s)", strerror(errno));
878 return -1;
879 }
880
881 bool ret = false;
882
883 if (!faccessat(dirfd, asecName, F_OK, AT_SYMLINK_NOFOLLOW)) {
884 ret = true;
885 }
886
887 close(dirfd);
888
889 return ret;
890}
891
892int VolumeManager::findAsec(const char *id, char *asecPath, size_t asecPathLen,
893 const char **directory) const {
894 int dirfd, fd;
895 const int idLen = strlen(id);
896 char *asecName;
897
898 if (asprintf(&asecName, "%s.asec", id) < 0) {
899 SLOGE("Couldn't allocate string to write ASEC name");
900 return -1;
901 }
902
903 const char *dir;
904 if (isAsecInDirectory(Volume::SEC_ASECDIR_INT, asecName)) {
905 dir = Volume::SEC_ASECDIR_INT;
906 } else if (isAsecInDirectory(Volume::SEC_ASECDIR_EXT, asecName)) {
907 dir = Volume::SEC_ASECDIR_EXT;
908 } else {
909 free(asecName);
910 return -1;
911 }
912
913 if (directory != NULL) {
914 *directory = dir;
915 }
916
917 if (asecPath != NULL) {
918 int written = snprintf(asecPath, asecPathLen, "%s/%s", dir, asecName);
rpcraigd1c226f2012-10-09 06:58:16 -0400919 if ((written < 0) || (size_t(written) >= asecPathLen)) {
920 SLOGE("findAsec failed for %s: couldn't construct ASEC path", id);
Kenny Root344ca102012-04-03 17:23:01 -0700921 free(asecName);
922 return -1;
923 }
924 }
925
926 free(asecName);
927 return 0;
928}
929
San Mehata19b2502010-01-06 10:33:53 -0800930int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
931 char asecFileName[255];
932 char mountPoint[255];
933
Kenny Root344ca102012-04-03 17:23:01 -0700934 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
935 SLOGE("Couldn't find ASEC %s", id);
936 return -1;
937 }
938
rpcraigd1c226f2012-10-09 06:58:16 -0400939 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
940 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
941 SLOGE("ASEC mount failed: couldn't construct mountpoint", id);
942 return -1;
943 }
San Mehata19b2502010-01-06 10:33:53 -0800944
945 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700946 SLOGE("ASEC %s already mounted", id);
San Mehata19b2502010-01-06 10:33:53 -0800947 errno = EBUSY;
948 return -1;
949 }
950
San Mehatd9a4e352010-03-12 13:32:47 -0800951 char idHash[33];
952 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700953 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800954 return -1;
955 }
Kenny Root7b18a7b2010-03-15 13:13:41 -0700956
San Mehata19b2502010-01-06 10:33:53 -0800957 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800958 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
959 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700960 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800961 return -1;
962 }
San Mehatd9a4e352010-03-12 13:32:47 -0800963 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700964 SLOGD("New loop device created at %s", loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800965 }
San Mehatb78a32c2010-01-10 13:02:12 -0800966 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800967 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700968 SLOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800969 }
San Mehatb78a32c2010-01-10 13:02:12 -0800970 }
971
972 char dmDevice[255];
973 bool cleanupDm = false;
San Mehatfcf24fe2010-03-03 12:37:32 -0800974 int fd;
975 unsigned int nr_sec = 0;
San Mehatfcf24fe2010-03-03 12:37:32 -0800976 struct asec_superblock sb;
San Mehatfcf24fe2010-03-03 12:37:32 -0800977
Kenny Root344ca102012-04-03 17:23:01 -0700978 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
979 return -1;
980 }
San Mehatfcf24fe2010-03-03 12:37:32 -0800981
San Mehatd9a4e352010-03-12 13:32:47 -0800982 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700983 SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatd9a4e352010-03-12 13:32:47 -0800984 }
San Mehatfcf24fe2010-03-03 12:37:32 -0800985 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
San Mehat97ac40e2010-03-24 10:24:19 -0700986 SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatfcf24fe2010-03-03 12:37:32 -0800987 Loop::destroyByDevice(loopDevice);
988 errno = EMEDIUMTYPE;
989 return -1;
990 }
991 nr_sec--; // We don't want the devmapping to extend onto our superblock
992
San Mehatb78a32c2010-01-10 13:02:12 -0800993 if (strcmp(key, "none")) {
San Mehatd9a4e352010-03-12 13:32:47 -0800994 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
995 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
San Mehatb78a32c2010-01-10 13:02:12 -0800996 dmDevice, sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700997 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800998 Loop::destroyByDevice(loopDevice);
999 return -1;
1000 }
San Mehatd9a4e352010-03-12 13:32:47 -08001001 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001002 SLOGD("New devmapper instance created at %s", dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -08001003 }
San Mehatb78a32c2010-01-10 13:02:12 -08001004 } else {
San Mehatd9a4e352010-03-12 13:32:47 -08001005 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001006 SLOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -08001007 }
San Mehatb78a32c2010-01-10 13:02:12 -08001008 }
1009 cleanupDm = true;
1010 } else {
1011 strcpy(dmDevice, loopDevice);
San Mehata19b2502010-01-06 10:33:53 -08001012 }
1013
Kenny Root344ca102012-04-03 17:23:01 -07001014 if (mkdir(mountPoint, 0000)) {
San Mehatb78a32c2010-01-10 13:02:12 -08001015 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -07001016 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001017 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -08001018 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -08001019 }
1020 Loop::destroyByDevice(loopDevice);
1021 return -1;
1022 }
San Mehata19b2502010-01-06 10:33:53 -08001023 }
1024
Kenny Rootcdc2a1c2012-05-03 13:49:46 -07001025 /*
1026 * The device mapper node needs to be created. Sometimes it takes a
1027 * while. Wait for up to 1 second. We could also inspect incoming uevents,
1028 * but that would take more effort.
1029 */
1030 int tries = 25;
1031 while (tries--) {
1032 if (!access(dmDevice, F_OK) || errno != ENOENT) {
1033 break;
1034 }
1035 usleep(40 * 1000);
1036 }
1037
Kenny Root344ca102012-04-03 17:23:01 -07001038 int result;
1039 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
1040 result = Ext4::doMount(dmDevice, mountPoint, true, false, true);
1041 } else {
1042 result = Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0, 0222, false);
1043 }
1044
1045 if (result) {
San Mehat97ac40e2010-03-24 10:24:19 -07001046 SLOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001047 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -08001048 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -08001049 }
1050 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -08001051 return -1;
1052 }
1053
Kenny Rootcbacf782010-09-24 15:11:48 -07001054 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehatd9a4e352010-03-12 13:32:47 -08001055 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001056 SLOGD("ASEC %s mounted", id);
San Mehatd9a4e352010-03-12 13:32:47 -08001057 }
San Mehata19b2502010-01-06 10:33:53 -08001058 return 0;
1059}
1060
Kenny Root93ecb382012-08-09 11:28:37 -07001061Volume* VolumeManager::getVolumeForFile(const char *fileName) {
1062 VolumeCollection::iterator i;
1063
1064 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
Jeff Sharkeyba6ae8d2013-07-15 18:14:25 -07001065 const char* mountPoint = (*i)->getFuseMountpoint();
Kenny Root93ecb382012-08-09 11:28:37 -07001066 if (!strncmp(fileName, mountPoint, strlen(mountPoint))) {
1067 return *i;
1068 }
1069 }
1070
1071 return NULL;
1072}
1073
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001074/**
1075 * Mounts an image file <code>img</code>.
1076 */
Jeff Sharkey69479042012-09-25 16:14:57 -07001077int VolumeManager::mountObb(const char *img, const char *key, int ownerGid) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001078 char mountPoint[255];
1079
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001080 char idHash[33];
1081 if (!asecHash(img, idHash, sizeof(idHash))) {
1082 SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
1083 return -1;
1084 }
1085
rpcraigd1c226f2012-10-09 06:58:16 -04001086 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
1087 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1088 SLOGE("OBB mount failed: couldn't construct mountpoint", img);
1089 return -1;
1090 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001091
1092 if (isMountpointMounted(mountPoint)) {
1093 SLOGE("Image %s already mounted", img);
1094 errno = EBUSY;
1095 return -1;
1096 }
1097
1098 char loopDevice[255];
1099 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
1100 if (Loop::create(idHash, img, loopDevice, sizeof(loopDevice))) {
1101 SLOGE("Image loop device creation failed (%s)", strerror(errno));
1102 return -1;
1103 }
1104 if (mDebug) {
1105 SLOGD("New loop device created at %s", loopDevice);
1106 }
1107 } else {
1108 if (mDebug) {
1109 SLOGD("Found active loopback for %s at %s", img, loopDevice);
1110 }
1111 }
1112
1113 char dmDevice[255];
1114 bool cleanupDm = false;
1115 int fd;
1116 unsigned int nr_sec = 0;
1117
1118 if ((fd = open(loopDevice, O_RDWR)) < 0) {
1119 SLOGE("Failed to open loopdevice (%s)", strerror(errno));
1120 Loop::destroyByDevice(loopDevice);
1121 return -1;
1122 }
1123
1124 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
1125 SLOGE("Failed to get loop size (%s)", strerror(errno));
1126 Loop::destroyByDevice(loopDevice);
1127 close(fd);
1128 return -1;
1129 }
1130
1131 close(fd);
1132
1133 if (strcmp(key, "none")) {
1134 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
1135 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
1136 dmDevice, sizeof(dmDevice))) {
1137 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
1138 Loop::destroyByDevice(loopDevice);
1139 return -1;
1140 }
1141 if (mDebug) {
1142 SLOGD("New devmapper instance created at %s", dmDevice);
1143 }
1144 } else {
1145 if (mDebug) {
1146 SLOGD("Found active devmapper for %s at %s", img, dmDevice);
1147 }
1148 }
1149 cleanupDm = true;
1150 } else {
1151 strcpy(dmDevice, loopDevice);
1152 }
1153
1154 if (mkdir(mountPoint, 0755)) {
1155 if (errno != EEXIST) {
1156 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
1157 if (cleanupDm) {
1158 Devmapper::destroy(idHash);
1159 }
1160 Loop::destroyByDevice(loopDevice);
1161 return -1;
1162 }
1163 }
1164
Jeff Sharkey69479042012-09-25 16:14:57 -07001165 if (Fat::doMount(dmDevice, mountPoint, true, false, true, 0, ownerGid,
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001166 0227, false)) {
1167 SLOGE("Image mount failed (%s)", strerror(errno));
1168 if (cleanupDm) {
1169 Devmapper::destroy(idHash);
1170 }
1171 Loop::destroyByDevice(loopDevice);
1172 return -1;
1173 }
1174
Kenny Rootcbacf782010-09-24 15:11:48 -07001175 mActiveContainers->push_back(new ContainerData(strdup(img), OBB));
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001176 if (mDebug) {
1177 SLOGD("Image %s mounted", img);
1178 }
1179 return 0;
1180}
1181
San Mehat49e2bce2009-10-12 16:29:01 -07001182int VolumeManager::mountVolume(const char *label) {
1183 Volume *v = lookupVolume(label);
1184
1185 if (!v) {
1186 errno = ENOENT;
1187 return -1;
1188 }
1189
San Mehata2677e42009-12-13 10:40:18 -08001190 return v->mountVol();
1191}
1192
Kenny Root508c0e12010-07-12 09:59:49 -07001193int VolumeManager::listMountedObbs(SocketClient* cli) {
1194 char device[256];
1195 char mount_path[256];
1196 char rest[256];
1197 FILE *fp;
1198 char line[1024];
1199
1200 if (!(fp = fopen("/proc/mounts", "r"))) {
1201 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
1202 return -1;
1203 }
1204
1205 // Create a string to compare against that has a trailing slash
Kenny Root93ecb382012-08-09 11:28:37 -07001206 int loopDirLen = strlen(Volume::LOOPDIR);
Kenny Root508c0e12010-07-12 09:59:49 -07001207 char loopDir[loopDirLen + 2];
1208 strcpy(loopDir, Volume::LOOPDIR);
1209 loopDir[loopDirLen++] = '/';
1210 loopDir[loopDirLen] = '\0';
1211
1212 while(fgets(line, sizeof(line), fp)) {
1213 line[strlen(line)-1] = '\0';
1214
1215 /*
1216 * Should look like:
1217 * /dev/block/loop0 /mnt/obb/fc99df1323fd36424f864dcb76b76d65 ...
1218 */
1219 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1220
1221 if (!strncmp(mount_path, loopDir, loopDirLen)) {
1222 int fd = open(device, O_RDONLY);
1223 if (fd >= 0) {
1224 struct loop_info64 li;
1225 if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
1226 cli->sendMsg(ResponseCode::AsecListResult,
1227 (const char*) li.lo_file_name, false);
1228 }
1229 close(fd);
1230 }
1231 }
1232 }
1233
1234 fclose(fp);
1235 return 0;
1236}
1237
San Mehateba65e92010-01-29 05:15:16 -08001238int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
1239 Volume *v = lookupVolume(label);
1240
1241 if (!v) {
1242 errno = ENOENT;
1243 return -1;
1244 }
1245
1246 if (strcmp(method, "ums")) {
1247 errno = ENOSYS;
1248 return -1;
1249 }
1250
1251 if (v->getState() != Volume::State_Shared) {
San Mehateba65e92010-01-29 05:15:16 -08001252 *enabled = false;
San Mehatb9aed742010-02-04 15:07:01 -08001253 } else {
1254 *enabled = true;
San Mehateba65e92010-01-29 05:15:16 -08001255 }
1256 return 0;
1257}
1258
San Mehata2677e42009-12-13 10:40:18 -08001259int VolumeManager::shareVolume(const char *label, const char *method) {
1260 Volume *v = lookupVolume(label);
1261
1262 if (!v) {
1263 errno = ENOENT;
1264 return -1;
1265 }
1266
1267 /*
1268 * Eventually, we'll want to support additional share back-ends,
1269 * some of which may work while the media is mounted. For now,
1270 * we just support UMS
1271 */
1272 if (strcmp(method, "ums")) {
1273 errno = ENOSYS;
1274 return -1;
1275 }
1276
1277 if (v->getState() == Volume::State_NoMedia) {
1278 errno = ENODEV;
1279 return -1;
1280 }
1281
San Mehat49e2bce2009-10-12 16:29:01 -07001282 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -08001283 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -07001284 errno = EBUSY;
1285 return -1;
1286 }
1287
Ken Sumrall3b170052011-07-11 15:38:57 -07001288 if (mVolManagerDisabled) {
1289 errno = EBUSY;
1290 return -1;
1291 }
1292
Mike Lockwood2dfe2972010-09-17 18:50:51 -04001293 dev_t d = v->getShareDevice();
San Mehata2677e42009-12-13 10:40:18 -08001294 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
1295 // This volume does not support raw disk access
1296 errno = EINVAL;
1297 return -1;
1298 }
1299
1300 int fd;
1301 char nodepath[255];
rpcraigd1c226f2012-10-09 06:58:16 -04001302 int written = snprintf(nodepath,
San Mehata2677e42009-12-13 10:40:18 -08001303 sizeof(nodepath), "/dev/block/vold/%d:%d",
Colin Cross346c5b22014-01-22 23:59:41 -08001304 major(d), minor(d));
San Mehata2677e42009-12-13 10:40:18 -08001305
rpcraigd1c226f2012-10-09 06:58:16 -04001306 if ((written < 0) || (size_t(written) >= sizeof(nodepath))) {
1307 SLOGE("shareVolume failed: couldn't construct nodepath");
1308 return -1;
1309 }
1310
Mike Lockwood97f2fc12011-06-07 10:51:38 -07001311 if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001312 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001313 return -1;
1314 }
1315
1316 if (write(fd, nodepath, strlen(nodepath)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001317 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001318 close(fd);
1319 return -1;
1320 }
1321
1322 close(fd);
1323 v->handleVolumeShared();
Mike Lockwooda28056b2010-10-28 15:21:24 -04001324 if (mUmsSharingCount++ == 0) {
1325 FILE* fp;
1326 mSavedDirtyRatio = -1; // in case we fail
1327 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1328 char line[16];
1329 if (fgets(line, sizeof(line), fp) && sscanf(line, "%d", &mSavedDirtyRatio)) {
1330 fprintf(fp, "%d\n", mUmsDirtyRatio);
1331 } else {
1332 SLOGE("Failed to read dirty_ratio (%s)", strerror(errno));
1333 }
1334 fclose(fp);
1335 } else {
1336 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1337 }
1338 }
San Mehata2677e42009-12-13 10:40:18 -08001339 return 0;
1340}
1341
1342int VolumeManager::unshareVolume(const char *label, const char *method) {
1343 Volume *v = lookupVolume(label);
1344
1345 if (!v) {
1346 errno = ENOENT;
1347 return -1;
1348 }
1349
1350 if (strcmp(method, "ums")) {
1351 errno = ENOSYS;
1352 return -1;
1353 }
1354
1355 if (v->getState() != Volume::State_Shared) {
1356 errno = EINVAL;
1357 return -1;
1358 }
1359
San Mehata2677e42009-12-13 10:40:18 -08001360 int fd;
Mike Lockwood97f2fc12011-06-07 10:51:38 -07001361 if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001362 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001363 return -1;
1364 }
1365
1366 char ch = 0;
1367 if (write(fd, &ch, 1) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001368 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001369 close(fd);
1370 return -1;
1371 }
1372
1373 close(fd);
1374 v->handleVolumeUnshared();
Mike Lockwooda28056b2010-10-28 15:21:24 -04001375 if (--mUmsSharingCount == 0 && mSavedDirtyRatio != -1) {
1376 FILE* fp;
1377 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1378 fprintf(fp, "%d\n", mSavedDirtyRatio);
1379 fclose(fp);
1380 } else {
1381 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1382 }
1383 mSavedDirtyRatio = -1;
1384 }
San Mehata2677e42009-12-13 10:40:18 -08001385 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -07001386}
1387
Ken Sumrall3b170052011-07-11 15:38:57 -07001388extern "C" int vold_disableVol(const char *label) {
Ken Sumrall29d8da82011-05-18 17:20:07 -07001389 VolumeManager *vm = VolumeManager::Instance();
Ken Sumrall3b170052011-07-11 15:38:57 -07001390 vm->disableVolumeManager();
1391 vm->unshareVolume(label, "ums");
Ken Sumrall0b8b5972011-08-31 16:14:23 -07001392 return vm->unmountVolume(label, true, false);
Ken Sumrall29d8da82011-05-18 17:20:07 -07001393}
1394
1395extern "C" int vold_getNumDirectVolumes(void) {
1396 VolumeManager *vm = VolumeManager::Instance();
1397 return vm->getNumDirectVolumes();
1398}
1399
1400int VolumeManager::getNumDirectVolumes(void) {
1401 VolumeCollection::iterator i;
1402 int n=0;
1403
1404 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1405 if ((*i)->getShareDevice() != (dev_t)0) {
1406 n++;
1407 }
1408 }
1409 return n;
1410}
1411
1412extern "C" int vold_getDirectVolumeList(struct volume_info *vol_list) {
1413 VolumeManager *vm = VolumeManager::Instance();
1414 return vm->getDirectVolumeList(vol_list);
1415}
1416
1417int VolumeManager::getDirectVolumeList(struct volume_info *vol_list) {
1418 VolumeCollection::iterator i;
1419 int n=0;
1420 dev_t d;
1421
1422 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1423 if ((d=(*i)->getShareDevice()) != (dev_t)0) {
1424 (*i)->getVolInfo(&vol_list[n]);
1425 snprintf(vol_list[n].blk_dev, sizeof(vol_list[n].blk_dev),
Colin Cross346c5b22014-01-22 23:59:41 -08001426 "/dev/block/vold/%d:%d", major(d), minor(d));
Ken Sumrall29d8da82011-05-18 17:20:07 -07001427 n++;
1428 }
1429 }
1430
1431 return 0;
1432}
1433
Ken Sumrall0b8b5972011-08-31 16:14:23 -07001434int VolumeManager::unmountVolume(const char *label, bool force, bool revert) {
San Mehat49e2bce2009-10-12 16:29:01 -07001435 Volume *v = lookupVolume(label);
1436
1437 if (!v) {
1438 errno = ENOENT;
1439 return -1;
1440 }
1441
San Mehata2677e42009-12-13 10:40:18 -08001442 if (v->getState() == Volume::State_NoMedia) {
1443 errno = ENODEV;
1444 return -1;
1445 }
1446
San Mehat49e2bce2009-10-12 16:29:01 -07001447 if (v->getState() != Volume::State_Mounted) {
San Mehat97ac40e2010-03-24 10:24:19 -07001448 SLOGW("Attempt to unmount volume which isn't mounted (%d)\n",
San Mehata2677e42009-12-13 10:40:18 -08001449 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -07001450 errno = EBUSY;
Ken Sumrall319b1042011-06-14 14:01:55 -07001451 return UNMOUNT_NOT_MOUNTED_ERR;
San Mehat49e2bce2009-10-12 16:29:01 -07001452 }
1453
San Mehat1a06eda2010-04-15 12:58:50 -07001454 cleanupAsec(v, force);
San Mehat88705162010-01-15 09:26:28 -08001455
Ken Sumrall0b8b5972011-08-31 16:14:23 -07001456 return v->unmountVol(force, revert);
San Mehat49e2bce2009-10-12 16:29:01 -07001457}
1458
Ken Sumrall425524d2012-06-14 20:55:28 -07001459extern "C" int vold_unmountAllAsecs(void) {
1460 int rc;
1461
1462 VolumeManager *vm = VolumeManager::Instance();
1463 rc = vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_EXT);
1464 if (vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_INT)) {
1465 rc = -1;
1466 }
1467 return rc;
1468}
1469
1470#define ID_BUF_LEN 256
1471#define ASEC_SUFFIX ".asec"
1472#define ASEC_SUFFIX_LEN (sizeof(ASEC_SUFFIX) - 1)
1473int VolumeManager::unmountAllAsecsInDir(const char *directory) {
1474 DIR *d = opendir(directory);
1475 int rc = 0;
1476
1477 if (!d) {
1478 SLOGE("Could not open asec dir %s", directory);
1479 return -1;
1480 }
1481
1482 size_t dirent_len = offsetof(struct dirent, d_name) +
Elliott Hughes8c480f72012-10-26 16:57:19 -07001483 fpathconf(dirfd(d), _PC_NAME_MAX) + 1;
Ken Sumrall425524d2012-06-14 20:55:28 -07001484
1485 struct dirent *dent = (struct dirent *) malloc(dirent_len);
1486 if (dent == NULL) {
1487 SLOGE("Failed to allocate memory for asec dir");
1488 return -1;
1489 }
1490
1491 struct dirent *result;
1492 while (!readdir_r(d, dent, &result) && result != NULL) {
1493 if (dent->d_name[0] == '.')
1494 continue;
1495 if (dent->d_type != DT_REG)
1496 continue;
1497 size_t name_len = strlen(dent->d_name);
1498 if (name_len > 5 && name_len < (ID_BUF_LEN + ASEC_SUFFIX_LEN - 1) &&
1499 !strcmp(&dent->d_name[name_len - 5], ASEC_SUFFIX)) {
1500 char id[ID_BUF_LEN];
1501 strlcpy(id, dent->d_name, name_len - 4);
1502 if (unmountAsec(id, true)) {
1503 /* Register the error, but try to unmount more asecs */
1504 rc = -1;
1505 }
1506 }
1507 }
1508 closedir(d);
1509
1510 free(dent);
1511
1512 return rc;
1513}
1514
San Mehata2677e42009-12-13 10:40:18 -08001515/*
1516 * Looks up a volume by it's label or mount-point
1517 */
San Mehat49e2bce2009-10-12 16:29:01 -07001518Volume *VolumeManager::lookupVolume(const char *label) {
1519 VolumeCollection::iterator i;
1520
1521 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -08001522 if (label[0] == '/') {
Jeff Sharkeyba6ae8d2013-07-15 18:14:25 -07001523 if (!strcmp(label, (*i)->getFuseMountpoint()))
San Mehata2677e42009-12-13 10:40:18 -08001524 return (*i);
1525 } else {
1526 if (!strcmp(label, (*i)->getLabel()))
1527 return (*i);
1528 }
San Mehat49e2bce2009-10-12 16:29:01 -07001529 }
1530 return NULL;
1531}
San Mehata19b2502010-01-06 10:33:53 -08001532
1533bool VolumeManager::isMountpointMounted(const char *mp)
1534{
1535 char device[256];
1536 char mount_path[256];
1537 char rest[256];
1538 FILE *fp;
1539 char line[1024];
1540
1541 if (!(fp = fopen("/proc/mounts", "r"))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001542 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001543 return false;
1544 }
1545
1546 while(fgets(line, sizeof(line), fp)) {
1547 line[strlen(line)-1] = '\0';
1548 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1549 if (!strcmp(mount_path, mp)) {
1550 fclose(fp);
1551 return true;
1552 }
San Mehata19b2502010-01-06 10:33:53 -08001553 }
1554
1555 fclose(fp);
1556 return false;
1557}
1558
San Mehat1a06eda2010-04-15 12:58:50 -07001559int VolumeManager::cleanupAsec(Volume *v, bool force) {
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001560 int rc = 0;
Kenny Root93ecb382012-08-09 11:28:37 -07001561
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001562 char asecFileName[255];
1563
1564 AsecIdCollection removeAsec;
1565 AsecIdCollection removeObb;
1566
Kenny Root93ecb382012-08-09 11:28:37 -07001567 for (AsecIdCollection::iterator it = mActiveContainers->begin(); it != mActiveContainers->end();
1568 ++it) {
Kenny Rootcbacf782010-09-24 15:11:48 -07001569 ContainerData* cd = *it;
Kenny Root93ecb382012-08-09 11:28:37 -07001570
Kenny Rootcbacf782010-09-24 15:11:48 -07001571 if (cd->type == ASEC) {
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001572 if (findAsec(cd->id, asecFileName, sizeof(asecFileName))) {
1573 SLOGE("Couldn't find ASEC %s; cleaning up", cd->id);
1574 removeAsec.push_back(cd);
1575 } else {
1576 SLOGD("Found ASEC at path %s", asecFileName);
1577 if (!strncmp(asecFileName, Volume::SEC_ASECDIR_EXT,
1578 strlen(Volume::SEC_ASECDIR_EXT))) {
1579 removeAsec.push_back(cd);
1580 }
1581 }
Kenny Rootcbacf782010-09-24 15:11:48 -07001582 } else if (cd->type == OBB) {
Kenny Root93ecb382012-08-09 11:28:37 -07001583 if (v == getVolumeForFile(cd->id)) {
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001584 removeObb.push_back(cd);
Kenny Rootcbacf782010-09-24 15:11:48 -07001585 }
1586 } else {
1587 SLOGE("Unknown container type %d!", cd->type);
San Mehat1a06eda2010-04-15 12:58:50 -07001588 }
1589 }
Kenny Root93ecb382012-08-09 11:28:37 -07001590
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001591 for (AsecIdCollection::iterator it = removeAsec.begin(); it != removeAsec.end(); ++it) {
Kenny Root93ecb382012-08-09 11:28:37 -07001592 ContainerData *cd = *it;
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001593 SLOGI("Unmounting ASEC %s (dependent on %s)", cd->id, v->getLabel());
1594 if (unmountAsec(cd->id, force)) {
1595 SLOGE("Failed to unmount ASEC %s (%s)", cd->id, strerror(errno));
1596 rc = -1;
1597 }
1598 }
1599
1600 for (AsecIdCollection::iterator it = removeObb.begin(); it != removeObb.end(); ++it) {
1601 ContainerData *cd = *it;
1602 SLOGI("Unmounting OBB %s (dependent on %s)", cd->id, v->getLabel());
Kenny Root93ecb382012-08-09 11:28:37 -07001603 if (unmountObb(cd->id, force)) {
1604 SLOGE("Failed to unmount OBB %s (%s)", cd->id, strerror(errno));
1605 rc = -1;
1606 }
1607 }
1608
1609 return rc;
San Mehat1a06eda2010-04-15 12:58:50 -07001610}
1611
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001612int VolumeManager::mkdirs(char* path) {
1613 // Require that path lives under a volume we manage
1614 const char* emulated_source = getenv("EMULATED_STORAGE_SOURCE");
1615 const char* root = NULL;
Marco Nelissen5ab02e72013-10-15 15:22:28 -07001616 if (emulated_source && !strncmp(path, emulated_source, strlen(emulated_source))) {
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001617 root = emulated_source;
1618 } else {
1619 Volume* vol = getVolumeForFile(path);
1620 if (vol) {
1621 root = vol->getMountpoint();
1622 }
1623 }
1624
1625 if (!root) {
1626 SLOGE("Failed to find volume for %s", path);
1627 return -EINVAL;
1628 }
1629
1630 /* fs_mkdirs() does symlink checking and relative path enforcement */
1631 return fs_mkdirs(path, 0700);
1632}