blob: 9889653666b71ef0a19ba23f38e9d739c0264e8e [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
Daniel Rosenberg6a74dca2014-05-23 13:47:00 -070057#define ROUND_UP_POWER_OF_2(number, po2) (((!!(number & ((1U << po2) - 1))) << po2)\
58 + (number & (~((1U << po2) - 1))))
59
San Mehatf1b736b2009-10-10 17:22:08 -070060VolumeManager *VolumeManager::sInstance = NULL;
61
62VolumeManager *VolumeManager::Instance() {
63 if (!sInstance)
64 sInstance = new VolumeManager();
65 return sInstance;
66}
67
68VolumeManager::VolumeManager() {
San Mehatd9a4e352010-03-12 13:32:47 -080069 mDebug = false;
San Mehatf1b736b2009-10-10 17:22:08 -070070 mVolumes = new VolumeCollection();
San Mehat88705162010-01-15 09:26:28 -080071 mActiveContainers = new AsecIdCollection();
San Mehatf1b736b2009-10-10 17:22:08 -070072 mBroadcaster = NULL;
Mike Lockwooda28056b2010-10-28 15:21:24 -040073 mUmsSharingCount = 0;
74 mSavedDirtyRatio = -1;
75 // set dirty ratio to 0 when UMS is active
76 mUmsDirtyRatio = 0;
Ken Sumrall3b170052011-07-11 15:38:57 -070077 mVolManagerDisabled = 0;
San Mehatf1b736b2009-10-10 17:22:08 -070078}
79
80VolumeManager::~VolumeManager() {
San Mehat88705162010-01-15 09:26:28 -080081 delete mVolumes;
82 delete mActiveContainers;
San Mehatf1b736b2009-10-10 17:22:08 -070083}
84
Kenny Root7b18a7b2010-03-15 13:13:41 -070085char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -070086 static const char* digits = "0123456789abcdef";
87
Kenny Root7b18a7b2010-03-15 13:13:41 -070088 unsigned char sig[MD5_DIGEST_LENGTH];
89
Kenny Rootacc9e7d2010-06-18 19:06:50 -070090 if (buffer == NULL) {
91 SLOGE("Destination buffer is NULL");
92 errno = ESPIPE;
93 return NULL;
94 } else if (id == NULL) {
95 SLOGE("Source buffer is NULL");
96 errno = ESPIPE;
97 return NULL;
98 } else if (len < MD5_ASCII_LENGTH_PLUS_NULL) {
Colin Cross59846b62014-02-06 20:34:29 -080099 SLOGE("Target hash buffer size < %d bytes (%zu)",
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700100 MD5_ASCII_LENGTH_PLUS_NULL, len);
San Mehatd9a4e352010-03-12 13:32:47 -0800101 errno = ESPIPE;
102 return NULL;
103 }
Kenny Root7b18a7b2010-03-15 13:13:41 -0700104
105 MD5(reinterpret_cast<const unsigned char*>(id), strlen(id), sig);
San Mehatd9a4e352010-03-12 13:32:47 -0800106
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700107 char *p = buffer;
Kenny Root7b18a7b2010-03-15 13:13:41 -0700108 for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700109 *p++ = digits[sig[i] >> 4];
110 *p++ = digits[sig[i] & 0x0F];
San Mehatd9a4e352010-03-12 13:32:47 -0800111 }
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700112 *p = '\0';
San Mehatd9a4e352010-03-12 13:32:47 -0800113
114 return buffer;
115}
116
117void VolumeManager::setDebug(bool enable) {
118 mDebug = enable;
119 VolumeCollection::iterator it;
120 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
121 (*it)->setDebug(enable);
122 }
123}
124
San Mehatf1b736b2009-10-10 17:22:08 -0700125int VolumeManager::start() {
126 return 0;
127}
128
129int VolumeManager::stop() {
130 return 0;
131}
132
133int VolumeManager::addVolume(Volume *v) {
134 mVolumes->push_back(v);
135 return 0;
136}
137
San Mehatfd7f5872009-10-12 11:32:47 -0700138void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
139 const char *devpath = evt->findParam("DEVPATH");
San Mehatf1b736b2009-10-10 17:22:08 -0700140
San Mehatfd7f5872009-10-12 11:32:47 -0700141 /* Lookup a volume to handle this device */
San Mehatf1b736b2009-10-10 17:22:08 -0700142 VolumeCollection::iterator it;
143 bool hit = false;
144 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
San Mehatfd7f5872009-10-12 11:32:47 -0700145 if (!(*it)->handleBlockEvent(evt)) {
San Mehata2677e42009-12-13 10:40:18 -0800146#ifdef NETLINK_DEBUG
San Mehat97ac40e2010-03-24 10:24:19 -0700147 SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
San Mehata2677e42009-12-13 10:40:18 -0800148#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700149 hit = true;
San Mehatf1b736b2009-10-10 17:22:08 -0700150 break;
151 }
152 }
153
154 if (!hit) {
San Mehata2677e42009-12-13 10:40:18 -0800155#ifdef NETLINK_DEBUG
San Mehat97ac40e2010-03-24 10:24:19 -0700156 SLOGW("No volumes handled block event for '%s'", devpath);
San Mehata2677e42009-12-13 10:40:18 -0800157#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700158 }
159}
160
San Mehatf1b736b2009-10-10 17:22:08 -0700161int VolumeManager::listVolumes(SocketClient *cli) {
162 VolumeCollection::iterator i;
163
164 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
165 char *buffer;
166 asprintf(&buffer, "%s %s %d",
Jeff Sharkeyba6ae8d2013-07-15 18:14:25 -0700167 (*i)->getLabel(), (*i)->getFuseMountpoint(),
San Mehatf1b736b2009-10-10 17:22:08 -0700168 (*i)->getState());
San Mehata2677e42009-12-13 10:40:18 -0800169 cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
San Mehatf1b736b2009-10-10 17:22:08 -0700170 free(buffer);
171 }
San Mehata2677e42009-12-13 10:40:18 -0800172 cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
San Mehatf1b736b2009-10-10 17:22:08 -0700173 return 0;
174}
San Mehat49e2bce2009-10-12 16:29:01 -0700175
Ken Sumrall9caab762013-06-11 19:10:20 -0700176int VolumeManager::formatVolume(const char *label, bool wipe) {
San Mehata2677e42009-12-13 10:40:18 -0800177 Volume *v = lookupVolume(label);
178
179 if (!v) {
180 errno = ENOENT;
181 return -1;
182 }
183
Ken Sumrall3b170052011-07-11 15:38:57 -0700184 if (mVolManagerDisabled) {
185 errno = EBUSY;
186 return -1;
187 }
188
Ken Sumrall9caab762013-06-11 19:10:20 -0700189 return v->formatVol(wipe);
San Mehata2677e42009-12-13 10:40:18 -0800190}
191
Kenny Root508c0e12010-07-12 09:59:49 -0700192int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) {
193 char idHash[33];
194 if (!asecHash(sourceFile, idHash, sizeof(idHash))) {
195 SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno));
196 return -1;
197 }
198
199 memset(mountPath, 0, mountPathLen);
rpcraigd1c226f2012-10-09 06:58:16 -0400200 int written = snprintf(mountPath, mountPathLen, "%s/%s", Volume::LOOPDIR, idHash);
201 if ((written < 0) || (written >= mountPathLen)) {
202 errno = EINVAL;
203 return -1;
204 }
Kenny Root508c0e12010-07-12 09:59:49 -0700205
206 if (access(mountPath, F_OK)) {
207 errno = ENOENT;
208 return -1;
209 }
210
211 return 0;
212}
213
San Mehata19b2502010-01-06 10:33:53 -0800214int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
San Mehat88ac2c02010-03-23 11:15:58 -0700215 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700216
Nick Kralevich0de7c612014-01-27 14:58:06 -0800217 if (!isLegalAsecId(id)) {
218 SLOGE("getAsecMountPath: Invalid asec id \"%s\"", id);
219 errno = EINVAL;
220 return -1;
221 }
222
Kenny Root344ca102012-04-03 17:23:01 -0700223 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
224 SLOGE("Couldn't find ASEC %s", id);
225 return -1;
226 }
San Mehat88ac2c02010-03-23 11:15:58 -0700227
228 memset(buffer, 0, maxlen);
229 if (access(asecFileName, F_OK)) {
230 errno = ENOENT;
231 return -1;
232 }
San Mehata19b2502010-01-06 10:33:53 -0800233
rpcraigd1c226f2012-10-09 06:58:16 -0400234 int written = snprintf(buffer, maxlen, "%s/%s", Volume::ASECDIR, id);
235 if ((written < 0) || (written >= maxlen)) {
236 SLOGE("getAsecMountPath failed for %s: couldn't construct path in buffer", id);
237 errno = EINVAL;
238 return -1;
239 }
240
San Mehata19b2502010-01-06 10:33:53 -0800241 return 0;
242}
243
Dianne Hackborn736910c2011-06-27 13:37:07 -0700244int VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxlen) {
245 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700246
Nick Kralevich0de7c612014-01-27 14:58:06 -0800247 if (!isLegalAsecId(id)) {
248 SLOGE("getAsecFilesystemPath: Invalid asec id \"%s\"", id);
249 errno = EINVAL;
250 return -1;
251 }
252
Kenny Root344ca102012-04-03 17:23:01 -0700253 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
254 SLOGE("Couldn't find ASEC %s", id);
255 return -1;
256 }
Dianne Hackborn736910c2011-06-27 13:37:07 -0700257
258 memset(buffer, 0, maxlen);
259 if (access(asecFileName, F_OK)) {
260 errno = ENOENT;
261 return -1;
262 }
263
rpcraigd1c226f2012-10-09 06:58:16 -0400264 int written = snprintf(buffer, maxlen, "%s", asecFileName);
265 if ((written < 0) || (written >= maxlen)) {
266 errno = EINVAL;
267 return -1;
268 }
269
Dianne Hackborn736910c2011-06-27 13:37:07 -0700270 return 0;
271}
272
Kenny Root344ca102012-04-03 17:23:01 -0700273int VolumeManager::createAsec(const char *id, unsigned int numSectors, const char *fstype,
274 const char *key, const int ownerUid, bool isExternal) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800275 struct asec_superblock sb;
276 memset(&sb, 0, sizeof(sb));
277
Nick Kralevich0de7c612014-01-27 14:58:06 -0800278 if (!isLegalAsecId(id)) {
279 SLOGE("createAsec: Invalid asec id \"%s\"", id);
280 errno = EINVAL;
281 return -1;
282 }
283
Kenny Root344ca102012-04-03 17:23:01 -0700284 const bool wantFilesystem = strcmp(fstype, "none");
285 bool usingExt4 = false;
286 if (wantFilesystem) {
287 usingExt4 = !strcmp(fstype, "ext4");
288 if (usingExt4) {
289 sb.c_opts |= ASEC_SB_C_OPTS_EXT4;
290 } else if (strcmp(fstype, "fat")) {
291 SLOGE("Invalid filesystem type %s", fstype);
292 errno = EINVAL;
293 return -1;
294 }
295 }
296
San Mehatfcf24fe2010-03-03 12:37:32 -0800297 sb.magic = ASEC_SB_MAGIC;
298 sb.ver = ASEC_SB_VER;
San Mehata19b2502010-01-06 10:33:53 -0800299
San Mehatd31e3802010-02-18 08:37:45 -0800300 if (numSectors < ((1024*1024)/512)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700301 SLOGE("Invalid container size specified (%d sectors)", numSectors);
San Mehatd31e3802010-02-18 08:37:45 -0800302 errno = EINVAL;
303 return -1;
304 }
305
San Mehata19b2502010-01-06 10:33:53 -0800306 if (lookupVolume(id)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700307 SLOGE("ASEC id '%s' currently exists", id);
San Mehata19b2502010-01-06 10:33:53 -0800308 errno = EADDRINUSE;
309 return -1;
310 }
311
312 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700313
314 if (!findAsec(id, asecFileName, sizeof(asecFileName))) {
315 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
316 asecFileName, strerror(errno));
317 errno = EADDRINUSE;
318 return -1;
319 }
320
321 const char *asecDir = isExternal ? Volume::SEC_ASECDIR_EXT : Volume::SEC_ASECDIR_INT;
322
rpcraigd1c226f2012-10-09 06:58:16 -0400323 int written = snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", asecDir, id);
324 if ((written < 0) || (size_t(written) >= sizeof(asecFileName))) {
325 errno = EINVAL;
326 return -1;
327 }
San Mehata19b2502010-01-06 10:33:53 -0800328
329 if (!access(asecFileName, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700330 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
Kenny Root344ca102012-04-03 17:23:01 -0700331 asecFileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800332 errno = EADDRINUSE;
333 return -1;
334 }
335
San Mehatfcf24fe2010-03-03 12:37:32 -0800336 /*
337 * Add some headroom
Daniel Rosenberg6a74dca2014-05-23 13:47:00 -0700338 * This is likely off by a bit, and we may want to do something different for ext4
San Mehatfcf24fe2010-03-03 12:37:32 -0800339 */
340 unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
341 unsigned numImgSectors = numSectors + fatSize + 2;
Daniel Rosenberg6a74dca2014-05-23 13:47:00 -0700342 /*
343 * ext4 is aligned to 4kb. fat is aligned to 32kb. Sectors are 512b.
344 */
345 if (usingExt4)
346 numImgSectors = ROUND_UP_POWER_OF_2(numImgSectors, 3);
347 else
348 numImgSectors = ROUND_UP_POWER_OF_2(numImgSectors, 6);
San Mehatfcf24fe2010-03-03 12:37:32 -0800349
350 // Add +1 for our superblock which is at the end
351 if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700352 SLOGE("ASEC image file creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800353 return -1;
354 }
355
San Mehatd9a4e352010-03-12 13:32:47 -0800356 char idHash[33];
357 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700358 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800359 unlink(asecFileName);
360 return -1;
361 }
362
San Mehata19b2502010-01-06 10:33:53 -0800363 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800364 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700365 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800366 unlink(asecFileName);
367 return -1;
368 }
369
San Mehatb78a32c2010-01-10 13:02:12 -0800370 char dmDevice[255];
371 bool cleanupDm = false;
San Mehata19b2502010-01-06 10:33:53 -0800372
San Mehatb78a32c2010-01-10 13:02:12 -0800373 if (strcmp(key, "none")) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800374 // XXX: This is all we support for now
375 sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
San Mehatd9a4e352010-03-12 13:32:47 -0800376 if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
San Mehatb78a32c2010-01-10 13:02:12 -0800377 sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700378 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800379 Loop::destroyByDevice(loopDevice);
380 unlink(asecFileName);
381 return -1;
382 }
383 cleanupDm = true;
384 } else {
San Mehatfcf24fe2010-03-03 12:37:32 -0800385 sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
San Mehatb78a32c2010-01-10 13:02:12 -0800386 strcpy(dmDevice, loopDevice);
387 }
388
San Mehatfcf24fe2010-03-03 12:37:32 -0800389 /*
390 * Drop down the superblock at the end of the file
391 */
392
393 int sbfd = open(loopDevice, O_RDWR);
394 if (sbfd < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700395 SLOGE("Failed to open new DM device for superblock write (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800396 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800397 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800398 }
399 Loop::destroyByDevice(loopDevice);
400 unlink(asecFileName);
401 return -1;
402 }
403
404 if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
405 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700406 SLOGE("Failed to lseek for superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800407 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800408 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800409 }
410 Loop::destroyByDevice(loopDevice);
411 unlink(asecFileName);
412 return -1;
413 }
414
415 if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) {
416 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700417 SLOGE("Failed to write superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800418 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800419 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800420 }
421 Loop::destroyByDevice(loopDevice);
422 unlink(asecFileName);
423 return -1;
424 }
425 close(sbfd);
426
Kenny Root344ca102012-04-03 17:23:01 -0700427 if (wantFilesystem) {
428 int formatStatus;
rpcraiga54e13a2012-09-21 14:17:08 -0400429 char mountPoint[255];
430
rpcraigd1c226f2012-10-09 06:58:16 -0400431 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
432 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
433 SLOGE("ASEC fs format failed: couldn't construct mountPoint");
434 if (cleanupDm) {
435 Devmapper::destroy(idHash);
436 }
437 Loop::destroyByDevice(loopDevice);
438 unlink(asecFileName);
439 return -1;
440 }
rpcraiga54e13a2012-09-21 14:17:08 -0400441
Kenny Root344ca102012-04-03 17:23:01 -0700442 if (usingExt4) {
Daniel Rosenberg6a74dca2014-05-23 13:47:00 -0700443 formatStatus = Ext4::format(dmDevice, numImgSectors, mountPoint);
Kenny Root344ca102012-04-03 17:23:01 -0700444 } else {
Ken Sumrall9caab762013-06-11 19:10:20 -0700445 formatStatus = Fat::format(dmDevice, numImgSectors, 0);
San Mehatb78a32c2010-01-10 13:02:12 -0800446 }
San Mehata19b2502010-01-06 10:33:53 -0800447
Kenny Root344ca102012-04-03 17:23:01 -0700448 if (formatStatus < 0) {
449 SLOGE("ASEC fs format failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800450 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800451 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800452 }
San Mehateb13a902010-01-07 12:12:50 -0800453 Loop::destroyByDevice(loopDevice);
454 unlink(asecFileName);
455 return -1;
456 }
Kenny Root344ca102012-04-03 17:23:01 -0700457
Kenny Root344ca102012-04-03 17:23:01 -0700458 if (mkdir(mountPoint, 0000)) {
San Mehata1091cb2010-02-28 20:17:20 -0800459 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -0700460 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800461 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800462 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800463 }
464 Loop::destroyByDevice(loopDevice);
465 unlink(asecFileName);
466 return -1;
467 }
San Mehatb78a32c2010-01-10 13:02:12 -0800468 }
San Mehata1091cb2010-02-28 20:17:20 -0800469
Kenny Root344ca102012-04-03 17:23:01 -0700470 int mountStatus;
471 if (usingExt4) {
472 mountStatus = Ext4::doMount(dmDevice, mountPoint, false, false, false);
473 } else {
474 mountStatus = Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid, 0, 0000,
475 false);
476 }
477
478 if (mountStatus) {
San Mehat97ac40e2010-03-24 10:24:19 -0700479 SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800480 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800481 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800482 }
483 Loop::destroyByDevice(loopDevice);
484 unlink(asecFileName);
485 return -1;
486 }
Kenny Root344ca102012-04-03 17:23:01 -0700487
488 if (usingExt4) {
489 int dirfd = open(mountPoint, O_DIRECTORY);
490 if (dirfd >= 0) {
491 if (fchown(dirfd, ownerUid, AID_SYSTEM)
492 || fchmod(dirfd, S_IRUSR | S_IWUSR | S_IXUSR | S_ISGID | S_IRGRP | S_IXGRP)) {
493 SLOGI("Cannot chown/chmod new ASEC mount point %s", mountPoint);
494 }
495 close(dirfd);
496 }
497 }
San Mehata1091cb2010-02-28 20:17:20 -0800498 } else {
San Mehat97ac40e2010-03-24 10:24:19 -0700499 SLOGI("Created raw secure container %s (no filesystem)", id);
San Mehata19b2502010-01-06 10:33:53 -0800500 }
San Mehat88705162010-01-15 09:26:28 -0800501
Kenny Rootcbacf782010-09-24 15:11:48 -0700502 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehata19b2502010-01-06 10:33:53 -0800503 return 0;
504}
505
506int VolumeManager::finalizeAsec(const char *id) {
507 char asecFileName[255];
508 char loopDevice[255];
509 char mountPoint[255];
510
Nick Kralevich0de7c612014-01-27 14:58:06 -0800511 if (!isLegalAsecId(id)) {
512 SLOGE("finalizeAsec: Invalid asec id \"%s\"", id);
513 errno = EINVAL;
514 return -1;
515 }
516
Kenny Root344ca102012-04-03 17:23:01 -0700517 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
518 SLOGE("Couldn't find ASEC %s", id);
519 return -1;
520 }
San Mehata19b2502010-01-06 10:33:53 -0800521
San Mehatd9a4e352010-03-12 13:32:47 -0800522 char idHash[33];
523 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700524 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800525 return -1;
526 }
527
528 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700529 SLOGE("Unable to finalize %s (%s)", id, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800530 return -1;
531 }
532
Kenny Root344ca102012-04-03 17:23:01 -0700533 unsigned int nr_sec = 0;
534 struct asec_superblock sb;
535
536 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
537 return -1;
538 }
539
rpcraigd1c226f2012-10-09 06:58:16 -0400540 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
541 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
542 SLOGE("ASEC finalize failed: couldn't construct mountPoint");
543 return -1;
544 }
Kenny Root344ca102012-04-03 17:23:01 -0700545
546 int result = 0;
547 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
548 result = Ext4::doMount(loopDevice, mountPoint, true, true, true);
549 } else {
550 result = Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false);
551 }
552
553 if (result) {
San Mehat97ac40e2010-03-24 10:24:19 -0700554 SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800555 return -1;
556 }
557
San Mehatd9a4e352010-03-12 13:32:47 -0800558 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700559 SLOGD("ASEC %s finalized", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800560 }
San Mehata19b2502010-01-06 10:33:53 -0800561 return 0;
562}
563
Kenny Root344ca102012-04-03 17:23:01 -0700564int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* filename) {
565 char asecFileName[255];
566 char loopDevice[255];
567 char mountPoint[255];
568
569 if (gid < AID_APP) {
570 SLOGE("Group ID is not in application range");
571 return -1;
572 }
573
Nick Kralevich0de7c612014-01-27 14:58:06 -0800574 if (!isLegalAsecId(id)) {
575 SLOGE("fixupAsecPermissions: Invalid asec id \"%s\"", id);
576 errno = EINVAL;
577 return -1;
578 }
579
Kenny Root344ca102012-04-03 17:23:01 -0700580 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
581 SLOGE("Couldn't find ASEC %s", id);
582 return -1;
583 }
584
585 char idHash[33];
586 if (!asecHash(id, idHash, sizeof(idHash))) {
587 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
588 return -1;
589 }
590
591 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
592 SLOGE("Unable fix permissions during lookup on %s (%s)", id, strerror(errno));
593 return -1;
594 }
595
596 unsigned int nr_sec = 0;
597 struct asec_superblock sb;
598
599 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
600 return -1;
601 }
602
rpcraigd1c226f2012-10-09 06:58:16 -0400603 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
604 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
605 SLOGE("Unable remount to fix permissions for %s: couldn't construct mountpoint", id);
606 return -1;
607 }
Kenny Root344ca102012-04-03 17:23:01 -0700608
609 int result = 0;
610 if ((sb.c_opts & ASEC_SB_C_OPTS_EXT4) == 0) {
611 return 0;
612 }
613
614 int ret = Ext4::doMount(loopDevice, mountPoint,
615 false /* read-only */,
616 true /* remount */,
617 false /* executable */);
618 if (ret) {
619 SLOGE("Unable remount to fix permissions for %s (%s)", id, strerror(errno));
620 return -1;
621 }
622
623 char *paths[] = { mountPoint, NULL };
624
625 FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL);
626 if (fts) {
627 // Traverse the entire hierarchy and chown to system UID.
628 for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
629 // We don't care about the lost+found directory.
630 if (!strcmp(ftsent->fts_name, "lost+found")) {
631 continue;
632 }
633
634 /*
635 * There can only be one file marked as private right now.
636 * This should be more robust, but it satisfies the requirements
637 * we have for right now.
638 */
639 const bool privateFile = !strcmp(ftsent->fts_name, filename);
640
641 int fd = open(ftsent->fts_accpath, O_NOFOLLOW);
642 if (fd < 0) {
643 SLOGE("Couldn't open file %s: %s", ftsent->fts_accpath, strerror(errno));
644 result = -1;
645 continue;
646 }
647
648 result |= fchown(fd, AID_SYSTEM, privateFile? gid : AID_SYSTEM);
649
650 if (ftsent->fts_info & FTS_D) {
Kenny Root1a673c82012-05-10 16:45:29 -0700651 result |= fchmod(fd, 0755);
Kenny Root348c8ab2012-05-10 15:39:53 -0700652 } else if (ftsent->fts_info & FTS_F) {
Kenny Root344ca102012-04-03 17:23:01 -0700653 result |= fchmod(fd, privateFile ? 0640 : 0644);
654 }
Robert Craigb9e3ba52014-02-04 10:53:00 -0500655
Stephen Smalley5093e612014-02-12 09:43:08 -0500656 if (selinux_android_restorecon(ftsent->fts_path, 0) < 0) {
Robert Craigb9e3ba52014-02-04 10:53:00 -0500657 SLOGE("restorecon failed for %s: %s\n", ftsent->fts_path, strerror(errno));
658 result |= -1;
659 }
660
Kenny Root344ca102012-04-03 17:23:01 -0700661 close(fd);
662 }
663 fts_close(fts);
664
665 // Finally make the directory readable by everyone.
666 int dirfd = open(mountPoint, O_DIRECTORY);
667 if (dirfd < 0 || fchmod(dirfd, 0755)) {
668 SLOGE("Couldn't change owner of existing directory %s: %s", mountPoint, strerror(errno));
669 result |= -1;
670 }
671 close(dirfd);
672 } else {
673 result |= -1;
674 }
675
676 result |= Ext4::doMount(loopDevice, mountPoint,
677 true /* read-only */,
678 true /* remount */,
679 true /* execute */);
680
681 if (result) {
682 SLOGE("ASEC fix permissions failed (%s)", strerror(errno));
683 return -1;
684 }
685
686 if (mDebug) {
687 SLOGD("ASEC %s permissions fixed", id);
688 }
689 return 0;
690}
691
San Mehat048b0802010-01-23 08:17:06 -0800692int VolumeManager::renameAsec(const char *id1, const char *id2) {
Kenny Root344ca102012-04-03 17:23:01 -0700693 char asecFilename1[255];
San Mehat048b0802010-01-23 08:17:06 -0800694 char *asecFilename2;
695 char mountPoint[255];
696
Kenny Root344ca102012-04-03 17:23:01 -0700697 const char *dir;
698
Nick Kralevich0de7c612014-01-27 14:58:06 -0800699 if (!isLegalAsecId(id1)) {
700 SLOGE("renameAsec: Invalid asec id1 \"%s\"", id1);
701 errno = EINVAL;
702 return -1;
703 }
704
705 if (!isLegalAsecId(id2)) {
706 SLOGE("renameAsec: Invalid asec id2 \"%s\"", id2);
707 errno = EINVAL;
708 return -1;
709 }
710
Kenny Root344ca102012-04-03 17:23:01 -0700711 if (findAsec(id1, asecFilename1, sizeof(asecFilename1), &dir)) {
712 SLOGE("Couldn't find ASEC %s", id1);
713 return -1;
714 }
715
716 asprintf(&asecFilename2, "%s/%s.asec", dir, id2);
San Mehat048b0802010-01-23 08:17:06 -0800717
rpcraigd1c226f2012-10-09 06:58:16 -0400718 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
719 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
720 SLOGE("Rename failed: couldn't construct mountpoint");
721 goto out_err;
722 }
723
San Mehat048b0802010-01-23 08:17:06 -0800724 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700725 SLOGW("Rename attempt when src mounted");
San Mehat048b0802010-01-23 08:17:06 -0800726 errno = EBUSY;
727 goto out_err;
728 }
729
rpcraigd1c226f2012-10-09 06:58:16 -0400730 written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2);
731 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
732 SLOGE("Rename failed: couldn't construct mountpoint2");
733 goto out_err;
734 }
735
San Mehat96956ed2010-02-24 08:42:51 -0800736 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700737 SLOGW("Rename attempt when dst mounted");
San Mehat96956ed2010-02-24 08:42:51 -0800738 errno = EBUSY;
739 goto out_err;
740 }
741
San Mehat048b0802010-01-23 08:17:06 -0800742 if (!access(asecFilename2, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700743 SLOGE("Rename attempt when dst exists");
San Mehat048b0802010-01-23 08:17:06 -0800744 errno = EADDRINUSE;
745 goto out_err;
746 }
747
748 if (rename(asecFilename1, asecFilename2)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700749 SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
San Mehat048b0802010-01-23 08:17:06 -0800750 goto out_err;
751 }
752
San Mehat048b0802010-01-23 08:17:06 -0800753 free(asecFilename2);
754 return 0;
755
756out_err:
San Mehat048b0802010-01-23 08:17:06 -0800757 free(asecFilename2);
758 return -1;
759}
760
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700761#define UNMOUNT_RETRIES 5
762#define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
San Mehat4ba89482010-02-18 09:00:18 -0800763int VolumeManager::unmountAsec(const char *id, bool force) {
San Mehata19b2502010-01-06 10:33:53 -0800764 char asecFileName[255];
765 char mountPoint[255];
766
Nick Kralevich0de7c612014-01-27 14:58:06 -0800767 if (!isLegalAsecId(id)) {
768 SLOGE("unmountAsec: Invalid asec id \"%s\"", id);
769 errno = EINVAL;
770 return -1;
771 }
772
Kenny Root344ca102012-04-03 17:23:01 -0700773 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
774 SLOGE("Couldn't find ASEC %s", id);
775 return -1;
776 }
777
rpcraigd1c226f2012-10-09 06:58:16 -0400778 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
779 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
780 SLOGE("ASEC unmount failed for %s: couldn't construct mountpoint", id);
781 return -1;
782 }
San Mehata19b2502010-01-06 10:33:53 -0800783
San Mehatd9a4e352010-03-12 13:32:47 -0800784 char idHash[33];
785 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700786 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800787 return -1;
788 }
789
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700790 return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
791}
792
Kenny Root508c0e12010-07-12 09:59:49 -0700793int VolumeManager::unmountObb(const char *fileName, bool force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700794 char mountPoint[255];
795
796 char idHash[33];
797 if (!asecHash(fileName, idHash, sizeof(idHash))) {
798 SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
799 return -1;
800 }
801
rpcraigd1c226f2012-10-09 06:58:16 -0400802 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
803 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
804 SLOGE("OBB unmount failed for %s: couldn't construct mountpoint", fileName);
805 return -1;
806 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700807
808 return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
809}
810
811int VolumeManager::unmountLoopImage(const char *id, const char *idHash,
812 const char *fileName, const char *mountPoint, bool force) {
San Mehat0586d542010-01-12 15:38:59 -0800813 if (!isMountpointMounted(mountPoint)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700814 SLOGE("Unmount request for %s when not mounted", id);
Kenny Root918e5f92010-09-30 18:00:52 -0700815 errno = ENOENT;
San Mehatb78a32c2010-01-10 13:02:12 -0800816 return -1;
817 }
San Mehat23969932010-01-09 07:08:06 -0800818
San Mehatb78a32c2010-01-10 13:02:12 -0800819 int i, rc;
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700820 for (i = 1; i <= UNMOUNT_RETRIES; i++) {
San Mehatb78a32c2010-01-10 13:02:12 -0800821 rc = umount(mountPoint);
822 if (!rc) {
823 break;
San Mehata19b2502010-01-06 10:33:53 -0800824 }
San Mehatb78a32c2010-01-10 13:02:12 -0800825 if (rc && (errno == EINVAL || errno == ENOENT)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700826 SLOGI("Container %s unmounted OK", id);
San Mehatb78a32c2010-01-10 13:02:12 -0800827 rc = 0;
828 break;
San Mehata19b2502010-01-06 10:33:53 -0800829 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700830 SLOGW("%s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -0800831 id, i, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800832
San Mehat4ba89482010-02-18 09:00:18 -0800833 int action = 0; // default is to just complain
834
835 if (force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700836 if (i > (UNMOUNT_RETRIES - 2))
San Mehat4ba89482010-02-18 09:00:18 -0800837 action = 2; // SIGKILL
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700838 else if (i > (UNMOUNT_RETRIES - 3))
San Mehat4ba89482010-02-18 09:00:18 -0800839 action = 1; // SIGHUP
840 }
San Mehat8c940ef2010-02-13 14:19:53 -0800841
San Mehat586536c2010-02-16 17:12:00 -0800842 Process::killProcessesWithOpenFiles(mountPoint, action);
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700843 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehatb78a32c2010-01-10 13:02:12 -0800844 }
845
846 if (rc) {
San Mehat4ba89482010-02-18 09:00:18 -0800847 errno = EBUSY;
San Mehat97ac40e2010-03-24 10:24:19 -0700848 SLOGE("Failed to unmount container %s (%s)", id, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800849 return -1;
850 }
851
San Mehat12f4b892010-02-24 11:43:22 -0800852 int retries = 10;
853
854 while(retries--) {
855 if (!rmdir(mountPoint)) {
856 break;
857 }
858
San Mehat97ac40e2010-03-24 10:24:19 -0700859 SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700860 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehat12f4b892010-02-24 11:43:22 -0800861 }
862
863 if (!retries) {
San Mehat97ac40e2010-03-24 10:24:19 -0700864 SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
San Mehatf5c61982010-02-03 11:04:46 -0800865 }
San Mehat88705162010-01-15 09:26:28 -0800866
San Mehatd9a4e352010-03-12 13:32:47 -0800867 if (Devmapper::destroy(idHash) && errno != ENXIO) {
San Mehat97ac40e2010-03-24 10:24:19 -0700868 SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800869 }
870
871 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800872 if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800873 Loop::destroyByDevice(loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800874 } else {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700875 SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800876 }
San Mehat88705162010-01-15 09:26:28 -0800877
878 AsecIdCollection::iterator it;
879 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
Kenny Rootcbacf782010-09-24 15:11:48 -0700880 ContainerData* cd = *it;
881 if (!strcmp(cd->id, id)) {
San Mehat88705162010-01-15 09:26:28 -0800882 free(*it);
883 mActiveContainers->erase(it);
884 break;
885 }
886 }
887 if (it == mActiveContainers->end()) {
San Mehat97ac40e2010-03-24 10:24:19 -0700888 SLOGW("mActiveContainers is inconsistent!");
San Mehat88705162010-01-15 09:26:28 -0800889 }
San Mehatb78a32c2010-01-10 13:02:12 -0800890 return 0;
891}
892
San Mehat4ba89482010-02-18 09:00:18 -0800893int VolumeManager::destroyAsec(const char *id, bool force) {
San Mehatb78a32c2010-01-10 13:02:12 -0800894 char asecFileName[255];
895 char mountPoint[255];
896
Nick Kralevich0de7c612014-01-27 14:58:06 -0800897 if (!isLegalAsecId(id)) {
898 SLOGE("destroyAsec: Invalid asec id \"%s\"", id);
899 errno = EINVAL;
900 return -1;
901 }
902
Kenny Root344ca102012-04-03 17:23:01 -0700903 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
904 SLOGE("Couldn't find ASEC %s", id);
905 return -1;
906 }
907
rpcraigd1c226f2012-10-09 06:58:16 -0400908 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
909 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
910 SLOGE("ASEC destroy failed for %s: couldn't construct mountpoint", id);
911 return -1;
912 }
San Mehatb78a32c2010-01-10 13:02:12 -0800913
San Mehat0586d542010-01-12 15:38:59 -0800914 if (isMountpointMounted(mountPoint)) {
San Mehatd9a4e352010-03-12 13:32:47 -0800915 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700916 SLOGD("Unmounting container before destroy");
San Mehatd9a4e352010-03-12 13:32:47 -0800917 }
San Mehat4ba89482010-02-18 09:00:18 -0800918 if (unmountAsec(id, force)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700919 SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800920 return -1;
921 }
922 }
San Mehata19b2502010-01-06 10:33:53 -0800923
San Mehat0586d542010-01-12 15:38:59 -0800924 if (unlink(asecFileName)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700925 SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800926 return -1;
927 }
San Mehata19b2502010-01-06 10:33:53 -0800928
San Mehatd9a4e352010-03-12 13:32:47 -0800929 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700930 SLOGD("ASEC %s destroyed", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800931 }
San Mehata19b2502010-01-06 10:33:53 -0800932 return 0;
933}
934
Nick Kralevich0de7c612014-01-27 14:58:06 -0800935/*
936 * Legal ASEC ids consist of alphanumeric characters, '-',
937 * '_', or '.'. ".." is not allowed. The first or last character
938 * of the ASEC id cannot be '.' (dot).
939 */
940bool VolumeManager::isLegalAsecId(const char *id) const {
941 size_t i;
942 size_t len = strlen(id);
943
944 if (len == 0) {
945 return false;
946 }
947 if ((id[0] == '.') || (id[len - 1] == '.')) {
948 return false;
949 }
950
951 for (i = 0; i < len; i++) {
952 if (id[i] == '.') {
953 // i=0 is guaranteed never to have a dot. See above.
954 if (id[i-1] == '.') return false;
955 continue;
956 }
957 if (id[i] == '_' || id[i] == '-') continue;
958 if (id[i] >= 'a' && id[i] <= 'z') continue;
959 if (id[i] >= 'A' && id[i] <= 'Z') continue;
960 if (id[i] >= '0' && id[i] <= '9') continue;
961 return false;
962 }
963
964 return true;
965}
966
Kenny Root344ca102012-04-03 17:23:01 -0700967bool VolumeManager::isAsecInDirectory(const char *dir, const char *asecName) const {
968 int dirfd = open(dir, O_DIRECTORY);
969 if (dirfd < 0) {
970 SLOGE("Couldn't open internal ASEC dir (%s)", strerror(errno));
971 return -1;
972 }
973
974 bool ret = false;
975
976 if (!faccessat(dirfd, asecName, F_OK, AT_SYMLINK_NOFOLLOW)) {
977 ret = true;
978 }
979
980 close(dirfd);
981
982 return ret;
983}
984
985int VolumeManager::findAsec(const char *id, char *asecPath, size_t asecPathLen,
986 const char **directory) const {
987 int dirfd, fd;
988 const int idLen = strlen(id);
989 char *asecName;
990
Nick Kralevich0de7c612014-01-27 14:58:06 -0800991 if (!isLegalAsecId(id)) {
992 SLOGE("findAsec: Invalid asec id \"%s\"", id);
993 errno = EINVAL;
994 return -1;
995 }
996
Kenny Root344ca102012-04-03 17:23:01 -0700997 if (asprintf(&asecName, "%s.asec", id) < 0) {
998 SLOGE("Couldn't allocate string to write ASEC name");
999 return -1;
1000 }
1001
1002 const char *dir;
1003 if (isAsecInDirectory(Volume::SEC_ASECDIR_INT, asecName)) {
1004 dir = Volume::SEC_ASECDIR_INT;
1005 } else if (isAsecInDirectory(Volume::SEC_ASECDIR_EXT, asecName)) {
1006 dir = Volume::SEC_ASECDIR_EXT;
1007 } else {
1008 free(asecName);
1009 return -1;
1010 }
1011
1012 if (directory != NULL) {
1013 *directory = dir;
1014 }
1015
1016 if (asecPath != NULL) {
1017 int written = snprintf(asecPath, asecPathLen, "%s/%s", dir, asecName);
rpcraigd1c226f2012-10-09 06:58:16 -04001018 if ((written < 0) || (size_t(written) >= asecPathLen)) {
1019 SLOGE("findAsec failed for %s: couldn't construct ASEC path", id);
Kenny Root344ca102012-04-03 17:23:01 -07001020 free(asecName);
1021 return -1;
1022 }
1023 }
1024
1025 free(asecName);
1026 return 0;
1027}
1028
San Mehata19b2502010-01-06 10:33:53 -08001029int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
1030 char asecFileName[255];
1031 char mountPoint[255];
1032
Nick Kralevich0de7c612014-01-27 14:58:06 -08001033 if (!isLegalAsecId(id)) {
1034 SLOGE("mountAsec: Invalid asec id \"%s\"", id);
1035 errno = EINVAL;
1036 return -1;
1037 }
1038
Kenny Root344ca102012-04-03 17:23:01 -07001039 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
1040 SLOGE("Couldn't find ASEC %s", id);
1041 return -1;
1042 }
1043
rpcraigd1c226f2012-10-09 06:58:16 -04001044 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
1045 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
Colin Cross59846b62014-02-06 20:34:29 -08001046 SLOGE("ASEC mount failed for %s: couldn't construct mountpoint", id);
rpcraigd1c226f2012-10-09 06:58:16 -04001047 return -1;
1048 }
San Mehata19b2502010-01-06 10:33:53 -08001049
1050 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001051 SLOGE("ASEC %s already mounted", id);
San Mehata19b2502010-01-06 10:33:53 -08001052 errno = EBUSY;
1053 return -1;
1054 }
1055
San Mehatd9a4e352010-03-12 13:32:47 -08001056 char idHash[33];
1057 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001058 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -08001059 return -1;
1060 }
Kenny Root7b18a7b2010-03-15 13:13:41 -07001061
San Mehata19b2502010-01-06 10:33:53 -08001062 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -08001063 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
1064 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001065 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001066 return -1;
1067 }
San Mehatd9a4e352010-03-12 13:32:47 -08001068 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001069 SLOGD("New loop device created at %s", loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -08001070 }
San Mehatb78a32c2010-01-10 13:02:12 -08001071 } else {
San Mehatd9a4e352010-03-12 13:32:47 -08001072 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001073 SLOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -08001074 }
San Mehatb78a32c2010-01-10 13:02:12 -08001075 }
1076
1077 char dmDevice[255];
1078 bool cleanupDm = false;
San Mehatfcf24fe2010-03-03 12:37:32 -08001079 int fd;
1080 unsigned int nr_sec = 0;
San Mehatfcf24fe2010-03-03 12:37:32 -08001081 struct asec_superblock sb;
San Mehatfcf24fe2010-03-03 12:37:32 -08001082
Kenny Root344ca102012-04-03 17:23:01 -07001083 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
1084 return -1;
1085 }
San Mehatfcf24fe2010-03-03 12:37:32 -08001086
San Mehatd9a4e352010-03-12 13:32:47 -08001087 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001088 SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatd9a4e352010-03-12 13:32:47 -08001089 }
San Mehatfcf24fe2010-03-03 12:37:32 -08001090 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
San Mehat97ac40e2010-03-24 10:24:19 -07001091 SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatfcf24fe2010-03-03 12:37:32 -08001092 Loop::destroyByDevice(loopDevice);
1093 errno = EMEDIUMTYPE;
1094 return -1;
1095 }
1096 nr_sec--; // We don't want the devmapping to extend onto our superblock
1097
San Mehatb78a32c2010-01-10 13:02:12 -08001098 if (strcmp(key, "none")) {
San Mehatd9a4e352010-03-12 13:32:47 -08001099 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
1100 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
San Mehatb78a32c2010-01-10 13:02:12 -08001101 dmDevice, sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001102 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001103 Loop::destroyByDevice(loopDevice);
1104 return -1;
1105 }
San Mehatd9a4e352010-03-12 13:32:47 -08001106 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001107 SLOGD("New devmapper instance created at %s", dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -08001108 }
San Mehatb78a32c2010-01-10 13:02:12 -08001109 } else {
San Mehatd9a4e352010-03-12 13:32:47 -08001110 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001111 SLOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -08001112 }
San Mehatb78a32c2010-01-10 13:02:12 -08001113 }
1114 cleanupDm = true;
1115 } else {
1116 strcpy(dmDevice, loopDevice);
San Mehata19b2502010-01-06 10:33:53 -08001117 }
1118
Kenny Root344ca102012-04-03 17:23:01 -07001119 if (mkdir(mountPoint, 0000)) {
San Mehatb78a32c2010-01-10 13:02:12 -08001120 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -07001121 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001122 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -08001123 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -08001124 }
1125 Loop::destroyByDevice(loopDevice);
1126 return -1;
1127 }
San Mehata19b2502010-01-06 10:33:53 -08001128 }
1129
Kenny Rootcdc2a1c2012-05-03 13:49:46 -07001130 /*
1131 * The device mapper node needs to be created. Sometimes it takes a
1132 * while. Wait for up to 1 second. We could also inspect incoming uevents,
1133 * but that would take more effort.
1134 */
1135 int tries = 25;
1136 while (tries--) {
1137 if (!access(dmDevice, F_OK) || errno != ENOENT) {
1138 break;
1139 }
1140 usleep(40 * 1000);
1141 }
1142
Kenny Root344ca102012-04-03 17:23:01 -07001143 int result;
1144 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
1145 result = Ext4::doMount(dmDevice, mountPoint, true, false, true);
1146 } else {
1147 result = Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0, 0222, false);
1148 }
1149
1150 if (result) {
San Mehat97ac40e2010-03-24 10:24:19 -07001151 SLOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001152 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -08001153 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -08001154 }
1155 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -08001156 return -1;
1157 }
1158
Kenny Rootcbacf782010-09-24 15:11:48 -07001159 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehatd9a4e352010-03-12 13:32:47 -08001160 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001161 SLOGD("ASEC %s mounted", id);
San Mehatd9a4e352010-03-12 13:32:47 -08001162 }
San Mehata19b2502010-01-06 10:33:53 -08001163 return 0;
1164}
1165
Kenny Root93ecb382012-08-09 11:28:37 -07001166Volume* VolumeManager::getVolumeForFile(const char *fileName) {
1167 VolumeCollection::iterator i;
1168
1169 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
Jeff Sharkeyba6ae8d2013-07-15 18:14:25 -07001170 const char* mountPoint = (*i)->getFuseMountpoint();
Kenny Root93ecb382012-08-09 11:28:37 -07001171 if (!strncmp(fileName, mountPoint, strlen(mountPoint))) {
1172 return *i;
1173 }
1174 }
1175
1176 return NULL;
1177}
1178
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001179/**
1180 * Mounts an image file <code>img</code>.
1181 */
Jeff Sharkey69479042012-09-25 16:14:57 -07001182int VolumeManager::mountObb(const char *img, const char *key, int ownerGid) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001183 char mountPoint[255];
1184
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001185 char idHash[33];
1186 if (!asecHash(img, idHash, sizeof(idHash))) {
1187 SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
1188 return -1;
1189 }
1190
rpcraigd1c226f2012-10-09 06:58:16 -04001191 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
1192 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
Colin Cross59846b62014-02-06 20:34:29 -08001193 SLOGE("OBB mount failed for %s: couldn't construct mountpoint", img);
rpcraigd1c226f2012-10-09 06:58:16 -04001194 return -1;
1195 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001196
1197 if (isMountpointMounted(mountPoint)) {
1198 SLOGE("Image %s already mounted", img);
1199 errno = EBUSY;
1200 return -1;
1201 }
1202
1203 char loopDevice[255];
1204 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
1205 if (Loop::create(idHash, img, loopDevice, sizeof(loopDevice))) {
1206 SLOGE("Image loop device creation failed (%s)", strerror(errno));
1207 return -1;
1208 }
1209 if (mDebug) {
1210 SLOGD("New loop device created at %s", loopDevice);
1211 }
1212 } else {
1213 if (mDebug) {
1214 SLOGD("Found active loopback for %s at %s", img, loopDevice);
1215 }
1216 }
1217
1218 char dmDevice[255];
1219 bool cleanupDm = false;
1220 int fd;
1221 unsigned int nr_sec = 0;
1222
1223 if ((fd = open(loopDevice, O_RDWR)) < 0) {
1224 SLOGE("Failed to open loopdevice (%s)", strerror(errno));
1225 Loop::destroyByDevice(loopDevice);
1226 return -1;
1227 }
1228
1229 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
1230 SLOGE("Failed to get loop size (%s)", strerror(errno));
1231 Loop::destroyByDevice(loopDevice);
1232 close(fd);
1233 return -1;
1234 }
1235
1236 close(fd);
1237
1238 if (strcmp(key, "none")) {
1239 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
1240 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
1241 dmDevice, sizeof(dmDevice))) {
1242 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
1243 Loop::destroyByDevice(loopDevice);
1244 return -1;
1245 }
1246 if (mDebug) {
1247 SLOGD("New devmapper instance created at %s", dmDevice);
1248 }
1249 } else {
1250 if (mDebug) {
1251 SLOGD("Found active devmapper for %s at %s", img, dmDevice);
1252 }
1253 }
1254 cleanupDm = true;
1255 } else {
1256 strcpy(dmDevice, loopDevice);
1257 }
1258
1259 if (mkdir(mountPoint, 0755)) {
1260 if (errno != EEXIST) {
1261 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
1262 if (cleanupDm) {
1263 Devmapper::destroy(idHash);
1264 }
1265 Loop::destroyByDevice(loopDevice);
1266 return -1;
1267 }
1268 }
1269
Jeff Sharkey69479042012-09-25 16:14:57 -07001270 if (Fat::doMount(dmDevice, mountPoint, true, false, true, 0, ownerGid,
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001271 0227, false)) {
1272 SLOGE("Image mount failed (%s)", strerror(errno));
1273 if (cleanupDm) {
1274 Devmapper::destroy(idHash);
1275 }
1276 Loop::destroyByDevice(loopDevice);
1277 return -1;
1278 }
1279
Kenny Rootcbacf782010-09-24 15:11:48 -07001280 mActiveContainers->push_back(new ContainerData(strdup(img), OBB));
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001281 if (mDebug) {
1282 SLOGD("Image %s mounted", img);
1283 }
1284 return 0;
1285}
1286
San Mehat49e2bce2009-10-12 16:29:01 -07001287int VolumeManager::mountVolume(const char *label) {
1288 Volume *v = lookupVolume(label);
1289
1290 if (!v) {
1291 errno = ENOENT;
1292 return -1;
1293 }
1294
San Mehata2677e42009-12-13 10:40:18 -08001295 return v->mountVol();
1296}
1297
Kenny Root508c0e12010-07-12 09:59:49 -07001298int VolumeManager::listMountedObbs(SocketClient* cli) {
1299 char device[256];
1300 char mount_path[256];
1301 char rest[256];
1302 FILE *fp;
1303 char line[1024];
1304
1305 if (!(fp = fopen("/proc/mounts", "r"))) {
1306 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
1307 return -1;
1308 }
1309
1310 // Create a string to compare against that has a trailing slash
Kenny Root93ecb382012-08-09 11:28:37 -07001311 int loopDirLen = strlen(Volume::LOOPDIR);
Kenny Root508c0e12010-07-12 09:59:49 -07001312 char loopDir[loopDirLen + 2];
1313 strcpy(loopDir, Volume::LOOPDIR);
1314 loopDir[loopDirLen++] = '/';
1315 loopDir[loopDirLen] = '\0';
1316
1317 while(fgets(line, sizeof(line), fp)) {
1318 line[strlen(line)-1] = '\0';
1319
1320 /*
1321 * Should look like:
1322 * /dev/block/loop0 /mnt/obb/fc99df1323fd36424f864dcb76b76d65 ...
1323 */
1324 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1325
1326 if (!strncmp(mount_path, loopDir, loopDirLen)) {
1327 int fd = open(device, O_RDONLY);
1328 if (fd >= 0) {
1329 struct loop_info64 li;
1330 if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
1331 cli->sendMsg(ResponseCode::AsecListResult,
1332 (const char*) li.lo_file_name, false);
1333 }
1334 close(fd);
1335 }
1336 }
1337 }
1338
1339 fclose(fp);
1340 return 0;
1341}
1342
San Mehateba65e92010-01-29 05:15:16 -08001343int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
1344 Volume *v = lookupVolume(label);
1345
1346 if (!v) {
1347 errno = ENOENT;
1348 return -1;
1349 }
1350
1351 if (strcmp(method, "ums")) {
1352 errno = ENOSYS;
1353 return -1;
1354 }
1355
1356 if (v->getState() != Volume::State_Shared) {
San Mehateba65e92010-01-29 05:15:16 -08001357 *enabled = false;
San Mehatb9aed742010-02-04 15:07:01 -08001358 } else {
1359 *enabled = true;
San Mehateba65e92010-01-29 05:15:16 -08001360 }
1361 return 0;
1362}
1363
San Mehata2677e42009-12-13 10:40:18 -08001364int VolumeManager::shareVolume(const char *label, const char *method) {
1365 Volume *v = lookupVolume(label);
1366
1367 if (!v) {
1368 errno = ENOENT;
1369 return -1;
1370 }
1371
1372 /*
1373 * Eventually, we'll want to support additional share back-ends,
1374 * some of which may work while the media is mounted. For now,
1375 * we just support UMS
1376 */
1377 if (strcmp(method, "ums")) {
1378 errno = ENOSYS;
1379 return -1;
1380 }
1381
1382 if (v->getState() == Volume::State_NoMedia) {
1383 errno = ENODEV;
1384 return -1;
1385 }
1386
San Mehat49e2bce2009-10-12 16:29:01 -07001387 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -08001388 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -07001389 errno = EBUSY;
1390 return -1;
1391 }
1392
Ken Sumrall3b170052011-07-11 15:38:57 -07001393 if (mVolManagerDisabled) {
1394 errno = EBUSY;
1395 return -1;
1396 }
1397
Mike Lockwood2dfe2972010-09-17 18:50:51 -04001398 dev_t d = v->getShareDevice();
San Mehata2677e42009-12-13 10:40:18 -08001399 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
1400 // This volume does not support raw disk access
1401 errno = EINVAL;
1402 return -1;
1403 }
1404
1405 int fd;
1406 char nodepath[255];
rpcraigd1c226f2012-10-09 06:58:16 -04001407 int written = snprintf(nodepath,
San Mehata2677e42009-12-13 10:40:18 -08001408 sizeof(nodepath), "/dev/block/vold/%d:%d",
Colin Cross346c5b22014-01-22 23:59:41 -08001409 major(d), minor(d));
San Mehata2677e42009-12-13 10:40:18 -08001410
rpcraigd1c226f2012-10-09 06:58:16 -04001411 if ((written < 0) || (size_t(written) >= sizeof(nodepath))) {
1412 SLOGE("shareVolume failed: couldn't construct nodepath");
1413 return -1;
1414 }
1415
Mike Lockwood97f2fc12011-06-07 10:51:38 -07001416 if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001417 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001418 return -1;
1419 }
1420
1421 if (write(fd, nodepath, strlen(nodepath)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001422 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001423 close(fd);
1424 return -1;
1425 }
1426
1427 close(fd);
1428 v->handleVolumeShared();
Mike Lockwooda28056b2010-10-28 15:21:24 -04001429 if (mUmsSharingCount++ == 0) {
1430 FILE* fp;
1431 mSavedDirtyRatio = -1; // in case we fail
1432 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1433 char line[16];
1434 if (fgets(line, sizeof(line), fp) && sscanf(line, "%d", &mSavedDirtyRatio)) {
1435 fprintf(fp, "%d\n", mUmsDirtyRatio);
1436 } else {
1437 SLOGE("Failed to read dirty_ratio (%s)", strerror(errno));
1438 }
1439 fclose(fp);
1440 } else {
1441 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1442 }
1443 }
San Mehata2677e42009-12-13 10:40:18 -08001444 return 0;
1445}
1446
1447int VolumeManager::unshareVolume(const char *label, const char *method) {
1448 Volume *v = lookupVolume(label);
1449
1450 if (!v) {
1451 errno = ENOENT;
1452 return -1;
1453 }
1454
1455 if (strcmp(method, "ums")) {
1456 errno = ENOSYS;
1457 return -1;
1458 }
1459
1460 if (v->getState() != Volume::State_Shared) {
1461 errno = EINVAL;
1462 return -1;
1463 }
1464
San Mehata2677e42009-12-13 10:40:18 -08001465 int fd;
Mike Lockwood97f2fc12011-06-07 10:51:38 -07001466 if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001467 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001468 return -1;
1469 }
1470
1471 char ch = 0;
1472 if (write(fd, &ch, 1) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001473 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001474 close(fd);
1475 return -1;
1476 }
1477
1478 close(fd);
1479 v->handleVolumeUnshared();
Mike Lockwooda28056b2010-10-28 15:21:24 -04001480 if (--mUmsSharingCount == 0 && mSavedDirtyRatio != -1) {
1481 FILE* fp;
1482 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1483 fprintf(fp, "%d\n", mSavedDirtyRatio);
1484 fclose(fp);
1485 } else {
1486 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1487 }
1488 mSavedDirtyRatio = -1;
1489 }
San Mehata2677e42009-12-13 10:40:18 -08001490 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -07001491}
1492
Ken Sumrall3b170052011-07-11 15:38:57 -07001493extern "C" int vold_disableVol(const char *label) {
Ken Sumrall29d8da82011-05-18 17:20:07 -07001494 VolumeManager *vm = VolumeManager::Instance();
Ken Sumrall3b170052011-07-11 15:38:57 -07001495 vm->disableVolumeManager();
1496 vm->unshareVolume(label, "ums");
Ken Sumrall0b8b5972011-08-31 16:14:23 -07001497 return vm->unmountVolume(label, true, false);
Ken Sumrall29d8da82011-05-18 17:20:07 -07001498}
1499
1500extern "C" int vold_getNumDirectVolumes(void) {
1501 VolumeManager *vm = VolumeManager::Instance();
1502 return vm->getNumDirectVolumes();
1503}
1504
1505int VolumeManager::getNumDirectVolumes(void) {
1506 VolumeCollection::iterator i;
1507 int n=0;
1508
1509 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1510 if ((*i)->getShareDevice() != (dev_t)0) {
1511 n++;
1512 }
1513 }
1514 return n;
1515}
1516
1517extern "C" int vold_getDirectVolumeList(struct volume_info *vol_list) {
1518 VolumeManager *vm = VolumeManager::Instance();
1519 return vm->getDirectVolumeList(vol_list);
1520}
1521
1522int VolumeManager::getDirectVolumeList(struct volume_info *vol_list) {
1523 VolumeCollection::iterator i;
1524 int n=0;
1525 dev_t d;
1526
1527 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1528 if ((d=(*i)->getShareDevice()) != (dev_t)0) {
1529 (*i)->getVolInfo(&vol_list[n]);
1530 snprintf(vol_list[n].blk_dev, sizeof(vol_list[n].blk_dev),
Colin Cross346c5b22014-01-22 23:59:41 -08001531 "/dev/block/vold/%d:%d", major(d), minor(d));
Ken Sumrall29d8da82011-05-18 17:20:07 -07001532 n++;
1533 }
1534 }
1535
1536 return 0;
1537}
1538
Ken Sumrall0b8b5972011-08-31 16:14:23 -07001539int VolumeManager::unmountVolume(const char *label, bool force, bool revert) {
San Mehat49e2bce2009-10-12 16:29:01 -07001540 Volume *v = lookupVolume(label);
1541
1542 if (!v) {
1543 errno = ENOENT;
1544 return -1;
1545 }
1546
San Mehata2677e42009-12-13 10:40:18 -08001547 if (v->getState() == Volume::State_NoMedia) {
1548 errno = ENODEV;
1549 return -1;
1550 }
1551
San Mehat49e2bce2009-10-12 16:29:01 -07001552 if (v->getState() != Volume::State_Mounted) {
San Mehat97ac40e2010-03-24 10:24:19 -07001553 SLOGW("Attempt to unmount volume which isn't mounted (%d)\n",
San Mehata2677e42009-12-13 10:40:18 -08001554 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -07001555 errno = EBUSY;
Ken Sumrall319b1042011-06-14 14:01:55 -07001556 return UNMOUNT_NOT_MOUNTED_ERR;
San Mehat49e2bce2009-10-12 16:29:01 -07001557 }
1558
San Mehat1a06eda2010-04-15 12:58:50 -07001559 cleanupAsec(v, force);
San Mehat88705162010-01-15 09:26:28 -08001560
Ken Sumrall0b8b5972011-08-31 16:14:23 -07001561 return v->unmountVol(force, revert);
San Mehat49e2bce2009-10-12 16:29:01 -07001562}
1563
Ken Sumrall425524d2012-06-14 20:55:28 -07001564extern "C" int vold_unmountAllAsecs(void) {
1565 int rc;
1566
1567 VolumeManager *vm = VolumeManager::Instance();
1568 rc = vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_EXT);
1569 if (vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_INT)) {
1570 rc = -1;
1571 }
1572 return rc;
1573}
1574
1575#define ID_BUF_LEN 256
1576#define ASEC_SUFFIX ".asec"
1577#define ASEC_SUFFIX_LEN (sizeof(ASEC_SUFFIX) - 1)
1578int VolumeManager::unmountAllAsecsInDir(const char *directory) {
1579 DIR *d = opendir(directory);
1580 int rc = 0;
1581
1582 if (!d) {
1583 SLOGE("Could not open asec dir %s", directory);
1584 return -1;
1585 }
1586
1587 size_t dirent_len = offsetof(struct dirent, d_name) +
Elliott Hughes8c480f72012-10-26 16:57:19 -07001588 fpathconf(dirfd(d), _PC_NAME_MAX) + 1;
Ken Sumrall425524d2012-06-14 20:55:28 -07001589
1590 struct dirent *dent = (struct dirent *) malloc(dirent_len);
1591 if (dent == NULL) {
1592 SLOGE("Failed to allocate memory for asec dir");
1593 return -1;
1594 }
1595
1596 struct dirent *result;
1597 while (!readdir_r(d, dent, &result) && result != NULL) {
1598 if (dent->d_name[0] == '.')
1599 continue;
1600 if (dent->d_type != DT_REG)
1601 continue;
1602 size_t name_len = strlen(dent->d_name);
1603 if (name_len > 5 && name_len < (ID_BUF_LEN + ASEC_SUFFIX_LEN - 1) &&
1604 !strcmp(&dent->d_name[name_len - 5], ASEC_SUFFIX)) {
1605 char id[ID_BUF_LEN];
1606 strlcpy(id, dent->d_name, name_len - 4);
1607 if (unmountAsec(id, true)) {
1608 /* Register the error, but try to unmount more asecs */
1609 rc = -1;
1610 }
1611 }
1612 }
1613 closedir(d);
1614
1615 free(dent);
1616
1617 return rc;
1618}
1619
San Mehata2677e42009-12-13 10:40:18 -08001620/*
1621 * Looks up a volume by it's label or mount-point
1622 */
San Mehat49e2bce2009-10-12 16:29:01 -07001623Volume *VolumeManager::lookupVolume(const char *label) {
1624 VolumeCollection::iterator i;
1625
1626 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -08001627 if (label[0] == '/') {
Jeff Sharkeyba6ae8d2013-07-15 18:14:25 -07001628 if (!strcmp(label, (*i)->getFuseMountpoint()))
San Mehata2677e42009-12-13 10:40:18 -08001629 return (*i);
1630 } else {
1631 if (!strcmp(label, (*i)->getLabel()))
1632 return (*i);
1633 }
San Mehat49e2bce2009-10-12 16:29:01 -07001634 }
1635 return NULL;
1636}
San Mehata19b2502010-01-06 10:33:53 -08001637
1638bool VolumeManager::isMountpointMounted(const char *mp)
1639{
1640 char device[256];
1641 char mount_path[256];
1642 char rest[256];
1643 FILE *fp;
1644 char line[1024];
1645
1646 if (!(fp = fopen("/proc/mounts", "r"))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001647 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001648 return false;
1649 }
1650
1651 while(fgets(line, sizeof(line), fp)) {
1652 line[strlen(line)-1] = '\0';
1653 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1654 if (!strcmp(mount_path, mp)) {
1655 fclose(fp);
1656 return true;
1657 }
San Mehata19b2502010-01-06 10:33:53 -08001658 }
1659
1660 fclose(fp);
1661 return false;
1662}
1663
San Mehat1a06eda2010-04-15 12:58:50 -07001664int VolumeManager::cleanupAsec(Volume *v, bool force) {
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001665 int rc = 0;
Kenny Root93ecb382012-08-09 11:28:37 -07001666
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001667 char asecFileName[255];
1668
1669 AsecIdCollection removeAsec;
1670 AsecIdCollection removeObb;
1671
Kenny Root93ecb382012-08-09 11:28:37 -07001672 for (AsecIdCollection::iterator it = mActiveContainers->begin(); it != mActiveContainers->end();
1673 ++it) {
Kenny Rootcbacf782010-09-24 15:11:48 -07001674 ContainerData* cd = *it;
Kenny Root93ecb382012-08-09 11:28:37 -07001675
Kenny Rootcbacf782010-09-24 15:11:48 -07001676 if (cd->type == ASEC) {
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001677 if (findAsec(cd->id, asecFileName, sizeof(asecFileName))) {
1678 SLOGE("Couldn't find ASEC %s; cleaning up", cd->id);
1679 removeAsec.push_back(cd);
1680 } else {
1681 SLOGD("Found ASEC at path %s", asecFileName);
1682 if (!strncmp(asecFileName, Volume::SEC_ASECDIR_EXT,
1683 strlen(Volume::SEC_ASECDIR_EXT))) {
1684 removeAsec.push_back(cd);
1685 }
1686 }
Kenny Rootcbacf782010-09-24 15:11:48 -07001687 } else if (cd->type == OBB) {
Kenny Root93ecb382012-08-09 11:28:37 -07001688 if (v == getVolumeForFile(cd->id)) {
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001689 removeObb.push_back(cd);
Kenny Rootcbacf782010-09-24 15:11:48 -07001690 }
1691 } else {
1692 SLOGE("Unknown container type %d!", cd->type);
San Mehat1a06eda2010-04-15 12:58:50 -07001693 }
1694 }
Kenny Root93ecb382012-08-09 11:28:37 -07001695
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001696 for (AsecIdCollection::iterator it = removeAsec.begin(); it != removeAsec.end(); ++it) {
Kenny Root93ecb382012-08-09 11:28:37 -07001697 ContainerData *cd = *it;
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001698 SLOGI("Unmounting ASEC %s (dependent on %s)", cd->id, v->getLabel());
1699 if (unmountAsec(cd->id, force)) {
1700 SLOGE("Failed to unmount ASEC %s (%s)", cd->id, strerror(errno));
1701 rc = -1;
1702 }
1703 }
1704
1705 for (AsecIdCollection::iterator it = removeObb.begin(); it != removeObb.end(); ++it) {
1706 ContainerData *cd = *it;
1707 SLOGI("Unmounting OBB %s (dependent on %s)", cd->id, v->getLabel());
Kenny Root93ecb382012-08-09 11:28:37 -07001708 if (unmountObb(cd->id, force)) {
1709 SLOGE("Failed to unmount OBB %s (%s)", cd->id, strerror(errno));
1710 rc = -1;
1711 }
1712 }
1713
1714 return rc;
San Mehat1a06eda2010-04-15 12:58:50 -07001715}
1716
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001717int VolumeManager::mkdirs(char* path) {
Cylen Yao27cfee32014-05-02 19:23:42 +08001718 // Require that path lives under a volume we manage and is mounted
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001719 const char* emulated_source = getenv("EMULATED_STORAGE_SOURCE");
1720 const char* root = NULL;
Marco Nelissen5ab02e72013-10-15 15:22:28 -07001721 if (emulated_source && !strncmp(path, emulated_source, strlen(emulated_source))) {
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001722 root = emulated_source;
1723 } else {
1724 Volume* vol = getVolumeForFile(path);
Cylen Yao27cfee32014-05-02 19:23:42 +08001725 if (vol && vol->getState() == Volume::State_Mounted) {
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001726 root = vol->getMountpoint();
1727 }
1728 }
1729
1730 if (!root) {
Cylen Yao27cfee32014-05-02 19:23:42 +08001731 SLOGE("Failed to find mounted volume for %s", path);
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001732 return -EINVAL;
1733 }
1734
1735 /* fs_mkdirs() does symlink checking and relative path enforcement */
1736 return fs_mkdirs(path, 0700);
1737}