blob: 1ffa93966cf2a3d46f6b3de6fbcbc8bad3b7d1ad [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) {
Colin Cross59846b62014-02-06 20:34:29 -080096 SLOGE("Target hash buffer size < %d bytes (%zu)",
Kenny Rootacc9e7d2010-06-18 19:06:50 -070097 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
Nick Kralevich0de7c612014-01-27 14:58:06 -0800214 if (!isLegalAsecId(id)) {
215 SLOGE("getAsecMountPath: Invalid asec id \"%s\"", id);
216 errno = EINVAL;
217 return -1;
218 }
219
Kenny Root344ca102012-04-03 17:23:01 -0700220 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
221 SLOGE("Couldn't find ASEC %s", id);
222 return -1;
223 }
San Mehat88ac2c02010-03-23 11:15:58 -0700224
225 memset(buffer, 0, maxlen);
226 if (access(asecFileName, F_OK)) {
227 errno = ENOENT;
228 return -1;
229 }
San Mehata19b2502010-01-06 10:33:53 -0800230
rpcraigd1c226f2012-10-09 06:58:16 -0400231 int written = snprintf(buffer, maxlen, "%s/%s", Volume::ASECDIR, id);
232 if ((written < 0) || (written >= maxlen)) {
233 SLOGE("getAsecMountPath failed for %s: couldn't construct path in buffer", id);
234 errno = EINVAL;
235 return -1;
236 }
237
San Mehata19b2502010-01-06 10:33:53 -0800238 return 0;
239}
240
Dianne Hackborn736910c2011-06-27 13:37:07 -0700241int VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxlen) {
242 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700243
Nick Kralevich0de7c612014-01-27 14:58:06 -0800244 if (!isLegalAsecId(id)) {
245 SLOGE("getAsecFilesystemPath: Invalid asec id \"%s\"", id);
246 errno = EINVAL;
247 return -1;
248 }
249
Kenny Root344ca102012-04-03 17:23:01 -0700250 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
251 SLOGE("Couldn't find ASEC %s", id);
252 return -1;
253 }
Dianne Hackborn736910c2011-06-27 13:37:07 -0700254
255 memset(buffer, 0, maxlen);
256 if (access(asecFileName, F_OK)) {
257 errno = ENOENT;
258 return -1;
259 }
260
rpcraigd1c226f2012-10-09 06:58:16 -0400261 int written = snprintf(buffer, maxlen, "%s", asecFileName);
262 if ((written < 0) || (written >= maxlen)) {
263 errno = EINVAL;
264 return -1;
265 }
266
Dianne Hackborn736910c2011-06-27 13:37:07 -0700267 return 0;
268}
269
Kenny Root344ca102012-04-03 17:23:01 -0700270int VolumeManager::createAsec(const char *id, unsigned int numSectors, const char *fstype,
271 const char *key, const int ownerUid, bool isExternal) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800272 struct asec_superblock sb;
273 memset(&sb, 0, sizeof(sb));
274
Nick Kralevich0de7c612014-01-27 14:58:06 -0800275 if (!isLegalAsecId(id)) {
276 SLOGE("createAsec: Invalid asec id \"%s\"", id);
277 errno = EINVAL;
278 return -1;
279 }
280
Kenny Root344ca102012-04-03 17:23:01 -0700281 const bool wantFilesystem = strcmp(fstype, "none");
282 bool usingExt4 = false;
283 if (wantFilesystem) {
284 usingExt4 = !strcmp(fstype, "ext4");
285 if (usingExt4) {
286 sb.c_opts |= ASEC_SB_C_OPTS_EXT4;
287 } else if (strcmp(fstype, "fat")) {
288 SLOGE("Invalid filesystem type %s", fstype);
289 errno = EINVAL;
290 return -1;
291 }
292 }
293
San Mehatfcf24fe2010-03-03 12:37:32 -0800294 sb.magic = ASEC_SB_MAGIC;
295 sb.ver = ASEC_SB_VER;
San Mehata19b2502010-01-06 10:33:53 -0800296
San Mehatd31e3802010-02-18 08:37:45 -0800297 if (numSectors < ((1024*1024)/512)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700298 SLOGE("Invalid container size specified (%d sectors)", numSectors);
San Mehatd31e3802010-02-18 08:37:45 -0800299 errno = EINVAL;
300 return -1;
301 }
302
San Mehata19b2502010-01-06 10:33:53 -0800303 if (lookupVolume(id)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700304 SLOGE("ASEC id '%s' currently exists", id);
San Mehata19b2502010-01-06 10:33:53 -0800305 errno = EADDRINUSE;
306 return -1;
307 }
308
309 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700310
311 if (!findAsec(id, asecFileName, sizeof(asecFileName))) {
312 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
313 asecFileName, strerror(errno));
314 errno = EADDRINUSE;
315 return -1;
316 }
317
318 const char *asecDir = isExternal ? Volume::SEC_ASECDIR_EXT : Volume::SEC_ASECDIR_INT;
319
rpcraigd1c226f2012-10-09 06:58:16 -0400320 int written = snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", asecDir, id);
321 if ((written < 0) || (size_t(written) >= sizeof(asecFileName))) {
322 errno = EINVAL;
323 return -1;
324 }
San Mehata19b2502010-01-06 10:33:53 -0800325
326 if (!access(asecFileName, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700327 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
Kenny Root344ca102012-04-03 17:23:01 -0700328 asecFileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800329 errno = EADDRINUSE;
330 return -1;
331 }
332
San Mehatfcf24fe2010-03-03 12:37:32 -0800333 /*
334 * Add some headroom
335 */
336 unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
337 unsigned numImgSectors = numSectors + fatSize + 2;
338
339 if (numImgSectors % 63) {
340 numImgSectors += (63 - (numImgSectors % 63));
341 }
342
343 // Add +1 for our superblock which is at the end
344 if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700345 SLOGE("ASEC image file creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800346 return -1;
347 }
348
San Mehatd9a4e352010-03-12 13:32:47 -0800349 char idHash[33];
350 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700351 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800352 unlink(asecFileName);
353 return -1;
354 }
355
San Mehata19b2502010-01-06 10:33:53 -0800356 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800357 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700358 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800359 unlink(asecFileName);
360 return -1;
361 }
362
San Mehatb78a32c2010-01-10 13:02:12 -0800363 char dmDevice[255];
364 bool cleanupDm = false;
San Mehata19b2502010-01-06 10:33:53 -0800365
San Mehatb78a32c2010-01-10 13:02:12 -0800366 if (strcmp(key, "none")) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800367 // XXX: This is all we support for now
368 sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
San Mehatd9a4e352010-03-12 13:32:47 -0800369 if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
San Mehatb78a32c2010-01-10 13:02:12 -0800370 sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700371 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800372 Loop::destroyByDevice(loopDevice);
373 unlink(asecFileName);
374 return -1;
375 }
376 cleanupDm = true;
377 } else {
San Mehatfcf24fe2010-03-03 12:37:32 -0800378 sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
San Mehatb78a32c2010-01-10 13:02:12 -0800379 strcpy(dmDevice, loopDevice);
380 }
381
San Mehatfcf24fe2010-03-03 12:37:32 -0800382 /*
383 * Drop down the superblock at the end of the file
384 */
385
386 int sbfd = open(loopDevice, O_RDWR);
387 if (sbfd < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700388 SLOGE("Failed to open new DM device for superblock write (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800389 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800390 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800391 }
392 Loop::destroyByDevice(loopDevice);
393 unlink(asecFileName);
394 return -1;
395 }
396
397 if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
398 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700399 SLOGE("Failed to lseek for superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800400 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800401 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800402 }
403 Loop::destroyByDevice(loopDevice);
404 unlink(asecFileName);
405 return -1;
406 }
407
408 if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) {
409 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700410 SLOGE("Failed to write superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800411 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800412 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800413 }
414 Loop::destroyByDevice(loopDevice);
415 unlink(asecFileName);
416 return -1;
417 }
418 close(sbfd);
419
Kenny Root344ca102012-04-03 17:23:01 -0700420 if (wantFilesystem) {
421 int formatStatus;
rpcraiga54e13a2012-09-21 14:17:08 -0400422 char mountPoint[255];
423
rpcraigd1c226f2012-10-09 06:58:16 -0400424 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
425 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
426 SLOGE("ASEC fs format failed: couldn't construct mountPoint");
427 if (cleanupDm) {
428 Devmapper::destroy(idHash);
429 }
430 Loop::destroyByDevice(loopDevice);
431 unlink(asecFileName);
432 return -1;
433 }
rpcraiga54e13a2012-09-21 14:17:08 -0400434
Kenny Root344ca102012-04-03 17:23:01 -0700435 if (usingExt4) {
rpcraiga54e13a2012-09-21 14:17:08 -0400436 formatStatus = Ext4::format(dmDevice, mountPoint);
Kenny Root344ca102012-04-03 17:23:01 -0700437 } else {
Ken Sumrall9caab762013-06-11 19:10:20 -0700438 formatStatus = Fat::format(dmDevice, numImgSectors, 0);
San Mehatb78a32c2010-01-10 13:02:12 -0800439 }
San Mehata19b2502010-01-06 10:33:53 -0800440
Kenny Root344ca102012-04-03 17:23:01 -0700441 if (formatStatus < 0) {
442 SLOGE("ASEC fs format failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800443 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800444 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800445 }
San Mehateb13a902010-01-07 12:12:50 -0800446 Loop::destroyByDevice(loopDevice);
447 unlink(asecFileName);
448 return -1;
449 }
Kenny Root344ca102012-04-03 17:23:01 -0700450
Kenny Root344ca102012-04-03 17:23:01 -0700451 if (mkdir(mountPoint, 0000)) {
San Mehata1091cb2010-02-28 20:17:20 -0800452 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -0700453 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800454 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800455 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800456 }
457 Loop::destroyByDevice(loopDevice);
458 unlink(asecFileName);
459 return -1;
460 }
San Mehatb78a32c2010-01-10 13:02:12 -0800461 }
San Mehata1091cb2010-02-28 20:17:20 -0800462
Kenny Root344ca102012-04-03 17:23:01 -0700463 int mountStatus;
464 if (usingExt4) {
465 mountStatus = Ext4::doMount(dmDevice, mountPoint, false, false, false);
466 } else {
467 mountStatus = Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid, 0, 0000,
468 false);
469 }
470
471 if (mountStatus) {
San Mehat97ac40e2010-03-24 10:24:19 -0700472 SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800473 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800474 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800475 }
476 Loop::destroyByDevice(loopDevice);
477 unlink(asecFileName);
478 return -1;
479 }
Kenny Root344ca102012-04-03 17:23:01 -0700480
481 if (usingExt4) {
482 int dirfd = open(mountPoint, O_DIRECTORY);
483 if (dirfd >= 0) {
484 if (fchown(dirfd, ownerUid, AID_SYSTEM)
485 || fchmod(dirfd, S_IRUSR | S_IWUSR | S_IXUSR | S_ISGID | S_IRGRP | S_IXGRP)) {
486 SLOGI("Cannot chown/chmod new ASEC mount point %s", mountPoint);
487 }
488 close(dirfd);
489 }
490 }
San Mehata1091cb2010-02-28 20:17:20 -0800491 } else {
San Mehat97ac40e2010-03-24 10:24:19 -0700492 SLOGI("Created raw secure container %s (no filesystem)", id);
San Mehata19b2502010-01-06 10:33:53 -0800493 }
San Mehat88705162010-01-15 09:26:28 -0800494
Kenny Rootcbacf782010-09-24 15:11:48 -0700495 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehata19b2502010-01-06 10:33:53 -0800496 return 0;
497}
498
499int VolumeManager::finalizeAsec(const char *id) {
500 char asecFileName[255];
501 char loopDevice[255];
502 char mountPoint[255];
503
Nick Kralevich0de7c612014-01-27 14:58:06 -0800504 if (!isLegalAsecId(id)) {
505 SLOGE("finalizeAsec: Invalid asec id \"%s\"", id);
506 errno = EINVAL;
507 return -1;
508 }
509
Kenny Root344ca102012-04-03 17:23:01 -0700510 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
511 SLOGE("Couldn't find ASEC %s", id);
512 return -1;
513 }
San Mehata19b2502010-01-06 10:33:53 -0800514
San Mehatd9a4e352010-03-12 13:32:47 -0800515 char idHash[33];
516 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700517 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800518 return -1;
519 }
520
521 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700522 SLOGE("Unable to finalize %s (%s)", id, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800523 return -1;
524 }
525
Kenny Root344ca102012-04-03 17:23:01 -0700526 unsigned int nr_sec = 0;
527 struct asec_superblock sb;
528
529 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
530 return -1;
531 }
532
rpcraigd1c226f2012-10-09 06:58:16 -0400533 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
534 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
535 SLOGE("ASEC finalize failed: couldn't construct mountPoint");
536 return -1;
537 }
Kenny Root344ca102012-04-03 17:23:01 -0700538
539 int result = 0;
540 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
541 result = Ext4::doMount(loopDevice, mountPoint, true, true, true);
542 } else {
543 result = Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false);
544 }
545
546 if (result) {
San Mehat97ac40e2010-03-24 10:24:19 -0700547 SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800548 return -1;
549 }
550
San Mehatd9a4e352010-03-12 13:32:47 -0800551 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700552 SLOGD("ASEC %s finalized", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800553 }
San Mehata19b2502010-01-06 10:33:53 -0800554 return 0;
555}
556
Kenny Root344ca102012-04-03 17:23:01 -0700557int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* filename) {
558 char asecFileName[255];
559 char loopDevice[255];
560 char mountPoint[255];
561
562 if (gid < AID_APP) {
563 SLOGE("Group ID is not in application range");
564 return -1;
565 }
566
Nick Kralevich0de7c612014-01-27 14:58:06 -0800567 if (!isLegalAsecId(id)) {
568 SLOGE("fixupAsecPermissions: Invalid asec id \"%s\"", id);
569 errno = EINVAL;
570 return -1;
571 }
572
Kenny Root344ca102012-04-03 17:23:01 -0700573 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
574 SLOGE("Couldn't find ASEC %s", id);
575 return -1;
576 }
577
578 char idHash[33];
579 if (!asecHash(id, idHash, sizeof(idHash))) {
580 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
581 return -1;
582 }
583
584 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
585 SLOGE("Unable fix permissions during lookup on %s (%s)", id, strerror(errno));
586 return -1;
587 }
588
589 unsigned int nr_sec = 0;
590 struct asec_superblock sb;
591
592 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
593 return -1;
594 }
595
rpcraigd1c226f2012-10-09 06:58:16 -0400596 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
597 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
598 SLOGE("Unable remount to fix permissions for %s: couldn't construct mountpoint", id);
599 return -1;
600 }
Kenny Root344ca102012-04-03 17:23:01 -0700601
602 int result = 0;
603 if ((sb.c_opts & ASEC_SB_C_OPTS_EXT4) == 0) {
604 return 0;
605 }
606
607 int ret = Ext4::doMount(loopDevice, mountPoint,
608 false /* read-only */,
609 true /* remount */,
610 false /* executable */);
611 if (ret) {
612 SLOGE("Unable remount to fix permissions for %s (%s)", id, strerror(errno));
613 return -1;
614 }
615
616 char *paths[] = { mountPoint, NULL };
617
618 FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL);
619 if (fts) {
620 // Traverse the entire hierarchy and chown to system UID.
621 for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
622 // We don't care about the lost+found directory.
623 if (!strcmp(ftsent->fts_name, "lost+found")) {
624 continue;
625 }
626
627 /*
628 * There can only be one file marked as private right now.
629 * This should be more robust, but it satisfies the requirements
630 * we have for right now.
631 */
632 const bool privateFile = !strcmp(ftsent->fts_name, filename);
633
634 int fd = open(ftsent->fts_accpath, O_NOFOLLOW);
635 if (fd < 0) {
636 SLOGE("Couldn't open file %s: %s", ftsent->fts_accpath, strerror(errno));
637 result = -1;
638 continue;
639 }
640
641 result |= fchown(fd, AID_SYSTEM, privateFile? gid : AID_SYSTEM);
642
643 if (ftsent->fts_info & FTS_D) {
Kenny Root1a673c82012-05-10 16:45:29 -0700644 result |= fchmod(fd, 0755);
Kenny Root348c8ab2012-05-10 15:39:53 -0700645 } else if (ftsent->fts_info & FTS_F) {
Kenny Root344ca102012-04-03 17:23:01 -0700646 result |= fchmod(fd, privateFile ? 0640 : 0644);
647 }
Robert Craigb9e3ba52014-02-04 10:53:00 -0500648
Stephen Smalley5093e612014-02-12 09:43:08 -0500649 if (selinux_android_restorecon(ftsent->fts_path, 0) < 0) {
Robert Craigb9e3ba52014-02-04 10:53:00 -0500650 SLOGE("restorecon failed for %s: %s\n", ftsent->fts_path, strerror(errno));
651 result |= -1;
652 }
653
Kenny Root344ca102012-04-03 17:23:01 -0700654 close(fd);
655 }
656 fts_close(fts);
657
658 // Finally make the directory readable by everyone.
659 int dirfd = open(mountPoint, O_DIRECTORY);
660 if (dirfd < 0 || fchmod(dirfd, 0755)) {
661 SLOGE("Couldn't change owner of existing directory %s: %s", mountPoint, strerror(errno));
662 result |= -1;
663 }
664 close(dirfd);
665 } else {
666 result |= -1;
667 }
668
669 result |= Ext4::doMount(loopDevice, mountPoint,
670 true /* read-only */,
671 true /* remount */,
672 true /* execute */);
673
674 if (result) {
675 SLOGE("ASEC fix permissions failed (%s)", strerror(errno));
676 return -1;
677 }
678
679 if (mDebug) {
680 SLOGD("ASEC %s permissions fixed", id);
681 }
682 return 0;
683}
684
San Mehat048b0802010-01-23 08:17:06 -0800685int VolumeManager::renameAsec(const char *id1, const char *id2) {
Kenny Root344ca102012-04-03 17:23:01 -0700686 char asecFilename1[255];
San Mehat048b0802010-01-23 08:17:06 -0800687 char *asecFilename2;
688 char mountPoint[255];
689
Kenny Root344ca102012-04-03 17:23:01 -0700690 const char *dir;
691
Nick Kralevich0de7c612014-01-27 14:58:06 -0800692 if (!isLegalAsecId(id1)) {
693 SLOGE("renameAsec: Invalid asec id1 \"%s\"", id1);
694 errno = EINVAL;
695 return -1;
696 }
697
698 if (!isLegalAsecId(id2)) {
699 SLOGE("renameAsec: Invalid asec id2 \"%s\"", id2);
700 errno = EINVAL;
701 return -1;
702 }
703
Kenny Root344ca102012-04-03 17:23:01 -0700704 if (findAsec(id1, asecFilename1, sizeof(asecFilename1), &dir)) {
705 SLOGE("Couldn't find ASEC %s", id1);
706 return -1;
707 }
708
709 asprintf(&asecFilename2, "%s/%s.asec", dir, id2);
San Mehat048b0802010-01-23 08:17:06 -0800710
rpcraigd1c226f2012-10-09 06:58:16 -0400711 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
712 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
713 SLOGE("Rename failed: couldn't construct mountpoint");
714 goto out_err;
715 }
716
San Mehat048b0802010-01-23 08:17:06 -0800717 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700718 SLOGW("Rename attempt when src mounted");
San Mehat048b0802010-01-23 08:17:06 -0800719 errno = EBUSY;
720 goto out_err;
721 }
722
rpcraigd1c226f2012-10-09 06:58:16 -0400723 written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2);
724 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
725 SLOGE("Rename failed: couldn't construct mountpoint2");
726 goto out_err;
727 }
728
San Mehat96956ed2010-02-24 08:42:51 -0800729 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700730 SLOGW("Rename attempt when dst mounted");
San Mehat96956ed2010-02-24 08:42:51 -0800731 errno = EBUSY;
732 goto out_err;
733 }
734
San Mehat048b0802010-01-23 08:17:06 -0800735 if (!access(asecFilename2, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700736 SLOGE("Rename attempt when dst exists");
San Mehat048b0802010-01-23 08:17:06 -0800737 errno = EADDRINUSE;
738 goto out_err;
739 }
740
741 if (rename(asecFilename1, asecFilename2)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700742 SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
San Mehat048b0802010-01-23 08:17:06 -0800743 goto out_err;
744 }
745
San Mehat048b0802010-01-23 08:17:06 -0800746 free(asecFilename2);
747 return 0;
748
749out_err:
San Mehat048b0802010-01-23 08:17:06 -0800750 free(asecFilename2);
751 return -1;
752}
753
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700754#define UNMOUNT_RETRIES 5
755#define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
San Mehat4ba89482010-02-18 09:00:18 -0800756int VolumeManager::unmountAsec(const char *id, bool force) {
San Mehata19b2502010-01-06 10:33:53 -0800757 char asecFileName[255];
758 char mountPoint[255];
759
Nick Kralevich0de7c612014-01-27 14:58:06 -0800760 if (!isLegalAsecId(id)) {
761 SLOGE("unmountAsec: Invalid asec id \"%s\"", id);
762 errno = EINVAL;
763 return -1;
764 }
765
Kenny Root344ca102012-04-03 17:23:01 -0700766 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
767 SLOGE("Couldn't find ASEC %s", id);
768 return -1;
769 }
770
rpcraigd1c226f2012-10-09 06:58:16 -0400771 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
772 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
773 SLOGE("ASEC unmount failed for %s: couldn't construct mountpoint", id);
774 return -1;
775 }
San Mehata19b2502010-01-06 10:33:53 -0800776
San Mehatd9a4e352010-03-12 13:32:47 -0800777 char idHash[33];
778 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700779 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800780 return -1;
781 }
782
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700783 return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
784}
785
Kenny Root508c0e12010-07-12 09:59:49 -0700786int VolumeManager::unmountObb(const char *fileName, bool force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700787 char mountPoint[255];
788
789 char idHash[33];
790 if (!asecHash(fileName, idHash, sizeof(idHash))) {
791 SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
792 return -1;
793 }
794
rpcraigd1c226f2012-10-09 06:58:16 -0400795 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
796 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
797 SLOGE("OBB unmount failed for %s: couldn't construct mountpoint", fileName);
798 return -1;
799 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700800
801 return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
802}
803
804int VolumeManager::unmountLoopImage(const char *id, const char *idHash,
805 const char *fileName, const char *mountPoint, bool force) {
San Mehat0586d542010-01-12 15:38:59 -0800806 if (!isMountpointMounted(mountPoint)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700807 SLOGE("Unmount request for %s when not mounted", id);
Kenny Root918e5f92010-09-30 18:00:52 -0700808 errno = ENOENT;
San Mehatb78a32c2010-01-10 13:02:12 -0800809 return -1;
810 }
San Mehat23969932010-01-09 07:08:06 -0800811
San Mehatb78a32c2010-01-10 13:02:12 -0800812 int i, rc;
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700813 for (i = 1; i <= UNMOUNT_RETRIES; i++) {
San Mehatb78a32c2010-01-10 13:02:12 -0800814 rc = umount(mountPoint);
815 if (!rc) {
816 break;
San Mehata19b2502010-01-06 10:33:53 -0800817 }
San Mehatb78a32c2010-01-10 13:02:12 -0800818 if (rc && (errno == EINVAL || errno == ENOENT)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700819 SLOGI("Container %s unmounted OK", id);
San Mehatb78a32c2010-01-10 13:02:12 -0800820 rc = 0;
821 break;
San Mehata19b2502010-01-06 10:33:53 -0800822 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700823 SLOGW("%s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -0800824 id, i, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800825
San Mehat4ba89482010-02-18 09:00:18 -0800826 int action = 0; // default is to just complain
827
828 if (force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700829 if (i > (UNMOUNT_RETRIES - 2))
San Mehat4ba89482010-02-18 09:00:18 -0800830 action = 2; // SIGKILL
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700831 else if (i > (UNMOUNT_RETRIES - 3))
San Mehat4ba89482010-02-18 09:00:18 -0800832 action = 1; // SIGHUP
833 }
San Mehat8c940ef2010-02-13 14:19:53 -0800834
San Mehat586536c2010-02-16 17:12:00 -0800835 Process::killProcessesWithOpenFiles(mountPoint, action);
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700836 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehatb78a32c2010-01-10 13:02:12 -0800837 }
838
839 if (rc) {
San Mehat4ba89482010-02-18 09:00:18 -0800840 errno = EBUSY;
San Mehat97ac40e2010-03-24 10:24:19 -0700841 SLOGE("Failed to unmount container %s (%s)", id, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800842 return -1;
843 }
844
San Mehat12f4b892010-02-24 11:43:22 -0800845 int retries = 10;
846
847 while(retries--) {
848 if (!rmdir(mountPoint)) {
849 break;
850 }
851
San Mehat97ac40e2010-03-24 10:24:19 -0700852 SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700853 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehat12f4b892010-02-24 11:43:22 -0800854 }
855
856 if (!retries) {
San Mehat97ac40e2010-03-24 10:24:19 -0700857 SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
San Mehatf5c61982010-02-03 11:04:46 -0800858 }
San Mehat88705162010-01-15 09:26:28 -0800859
San Mehatd9a4e352010-03-12 13:32:47 -0800860 if (Devmapper::destroy(idHash) && errno != ENXIO) {
San Mehat97ac40e2010-03-24 10:24:19 -0700861 SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800862 }
863
864 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800865 if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800866 Loop::destroyByDevice(loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800867 } else {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700868 SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800869 }
San Mehat88705162010-01-15 09:26:28 -0800870
871 AsecIdCollection::iterator it;
872 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
Kenny Rootcbacf782010-09-24 15:11:48 -0700873 ContainerData* cd = *it;
874 if (!strcmp(cd->id, id)) {
San Mehat88705162010-01-15 09:26:28 -0800875 free(*it);
876 mActiveContainers->erase(it);
877 break;
878 }
879 }
880 if (it == mActiveContainers->end()) {
San Mehat97ac40e2010-03-24 10:24:19 -0700881 SLOGW("mActiveContainers is inconsistent!");
San Mehat88705162010-01-15 09:26:28 -0800882 }
San Mehatb78a32c2010-01-10 13:02:12 -0800883 return 0;
884}
885
San Mehat4ba89482010-02-18 09:00:18 -0800886int VolumeManager::destroyAsec(const char *id, bool force) {
San Mehatb78a32c2010-01-10 13:02:12 -0800887 char asecFileName[255];
888 char mountPoint[255];
889
Nick Kralevich0de7c612014-01-27 14:58:06 -0800890 if (!isLegalAsecId(id)) {
891 SLOGE("destroyAsec: Invalid asec id \"%s\"", id);
892 errno = EINVAL;
893 return -1;
894 }
895
Kenny Root344ca102012-04-03 17:23:01 -0700896 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
897 SLOGE("Couldn't find ASEC %s", id);
898 return -1;
899 }
900
rpcraigd1c226f2012-10-09 06:58:16 -0400901 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
902 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
903 SLOGE("ASEC destroy failed for %s: couldn't construct mountpoint", id);
904 return -1;
905 }
San Mehatb78a32c2010-01-10 13:02:12 -0800906
San Mehat0586d542010-01-12 15:38:59 -0800907 if (isMountpointMounted(mountPoint)) {
San Mehatd9a4e352010-03-12 13:32:47 -0800908 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700909 SLOGD("Unmounting container before destroy");
San Mehatd9a4e352010-03-12 13:32:47 -0800910 }
San Mehat4ba89482010-02-18 09:00:18 -0800911 if (unmountAsec(id, force)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700912 SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800913 return -1;
914 }
915 }
San Mehata19b2502010-01-06 10:33:53 -0800916
San Mehat0586d542010-01-12 15:38:59 -0800917 if (unlink(asecFileName)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700918 SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800919 return -1;
920 }
San Mehata19b2502010-01-06 10:33:53 -0800921
San Mehatd9a4e352010-03-12 13:32:47 -0800922 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700923 SLOGD("ASEC %s destroyed", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800924 }
San Mehata19b2502010-01-06 10:33:53 -0800925 return 0;
926}
927
Nick Kralevich0de7c612014-01-27 14:58:06 -0800928/*
929 * Legal ASEC ids consist of alphanumeric characters, '-',
930 * '_', or '.'. ".." is not allowed. The first or last character
931 * of the ASEC id cannot be '.' (dot).
932 */
933bool VolumeManager::isLegalAsecId(const char *id) const {
934 size_t i;
935 size_t len = strlen(id);
936
937 if (len == 0) {
938 return false;
939 }
940 if ((id[0] == '.') || (id[len - 1] == '.')) {
941 return false;
942 }
943
944 for (i = 0; i < len; i++) {
945 if (id[i] == '.') {
946 // i=0 is guaranteed never to have a dot. See above.
947 if (id[i-1] == '.') return false;
948 continue;
949 }
950 if (id[i] == '_' || id[i] == '-') continue;
951 if (id[i] >= 'a' && id[i] <= 'z') continue;
952 if (id[i] >= 'A' && id[i] <= 'Z') continue;
953 if (id[i] >= '0' && id[i] <= '9') continue;
954 return false;
955 }
956
957 return true;
958}
959
Kenny Root344ca102012-04-03 17:23:01 -0700960bool VolumeManager::isAsecInDirectory(const char *dir, const char *asecName) const {
961 int dirfd = open(dir, O_DIRECTORY);
962 if (dirfd < 0) {
963 SLOGE("Couldn't open internal ASEC dir (%s)", strerror(errno));
964 return -1;
965 }
966
967 bool ret = false;
968
969 if (!faccessat(dirfd, asecName, F_OK, AT_SYMLINK_NOFOLLOW)) {
970 ret = true;
971 }
972
973 close(dirfd);
974
975 return ret;
976}
977
978int VolumeManager::findAsec(const char *id, char *asecPath, size_t asecPathLen,
979 const char **directory) const {
980 int dirfd, fd;
981 const int idLen = strlen(id);
982 char *asecName;
983
Nick Kralevich0de7c612014-01-27 14:58:06 -0800984 if (!isLegalAsecId(id)) {
985 SLOGE("findAsec: Invalid asec id \"%s\"", id);
986 errno = EINVAL;
987 return -1;
988 }
989
Kenny Root344ca102012-04-03 17:23:01 -0700990 if (asprintf(&asecName, "%s.asec", id) < 0) {
991 SLOGE("Couldn't allocate string to write ASEC name");
992 return -1;
993 }
994
995 const char *dir;
996 if (isAsecInDirectory(Volume::SEC_ASECDIR_INT, asecName)) {
997 dir = Volume::SEC_ASECDIR_INT;
998 } else if (isAsecInDirectory(Volume::SEC_ASECDIR_EXT, asecName)) {
999 dir = Volume::SEC_ASECDIR_EXT;
1000 } else {
1001 free(asecName);
1002 return -1;
1003 }
1004
1005 if (directory != NULL) {
1006 *directory = dir;
1007 }
1008
1009 if (asecPath != NULL) {
1010 int written = snprintf(asecPath, asecPathLen, "%s/%s", dir, asecName);
rpcraigd1c226f2012-10-09 06:58:16 -04001011 if ((written < 0) || (size_t(written) >= asecPathLen)) {
1012 SLOGE("findAsec failed for %s: couldn't construct ASEC path", id);
Kenny Root344ca102012-04-03 17:23:01 -07001013 free(asecName);
1014 return -1;
1015 }
1016 }
1017
1018 free(asecName);
1019 return 0;
1020}
1021
San Mehata19b2502010-01-06 10:33:53 -08001022int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
1023 char asecFileName[255];
1024 char mountPoint[255];
1025
Nick Kralevich0de7c612014-01-27 14:58:06 -08001026 if (!isLegalAsecId(id)) {
1027 SLOGE("mountAsec: Invalid asec id \"%s\"", id);
1028 errno = EINVAL;
1029 return -1;
1030 }
1031
Kenny Root344ca102012-04-03 17:23:01 -07001032 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
1033 SLOGE("Couldn't find ASEC %s", id);
1034 return -1;
1035 }
1036
rpcraigd1c226f2012-10-09 06:58:16 -04001037 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
1038 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
Colin Cross59846b62014-02-06 20:34:29 -08001039 SLOGE("ASEC mount failed for %s: couldn't construct mountpoint", id);
rpcraigd1c226f2012-10-09 06:58:16 -04001040 return -1;
1041 }
San Mehata19b2502010-01-06 10:33:53 -08001042
1043 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001044 SLOGE("ASEC %s already mounted", id);
San Mehata19b2502010-01-06 10:33:53 -08001045 errno = EBUSY;
1046 return -1;
1047 }
1048
San Mehatd9a4e352010-03-12 13:32:47 -08001049 char idHash[33];
1050 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001051 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -08001052 return -1;
1053 }
Kenny Root7b18a7b2010-03-15 13:13:41 -07001054
San Mehata19b2502010-01-06 10:33:53 -08001055 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -08001056 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
1057 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001058 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001059 return -1;
1060 }
San Mehatd9a4e352010-03-12 13:32:47 -08001061 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001062 SLOGD("New loop device created at %s", loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -08001063 }
San Mehatb78a32c2010-01-10 13:02:12 -08001064 } else {
San Mehatd9a4e352010-03-12 13:32:47 -08001065 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001066 SLOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -08001067 }
San Mehatb78a32c2010-01-10 13:02:12 -08001068 }
1069
1070 char dmDevice[255];
1071 bool cleanupDm = false;
San Mehatfcf24fe2010-03-03 12:37:32 -08001072 int fd;
1073 unsigned int nr_sec = 0;
San Mehatfcf24fe2010-03-03 12:37:32 -08001074 struct asec_superblock sb;
San Mehatfcf24fe2010-03-03 12:37:32 -08001075
Kenny Root344ca102012-04-03 17:23:01 -07001076 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
1077 return -1;
1078 }
San Mehatfcf24fe2010-03-03 12:37:32 -08001079
San Mehatd9a4e352010-03-12 13:32:47 -08001080 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001081 SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatd9a4e352010-03-12 13:32:47 -08001082 }
San Mehatfcf24fe2010-03-03 12:37:32 -08001083 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
San Mehat97ac40e2010-03-24 10:24:19 -07001084 SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatfcf24fe2010-03-03 12:37:32 -08001085 Loop::destroyByDevice(loopDevice);
1086 errno = EMEDIUMTYPE;
1087 return -1;
1088 }
1089 nr_sec--; // We don't want the devmapping to extend onto our superblock
1090
San Mehatb78a32c2010-01-10 13:02:12 -08001091 if (strcmp(key, "none")) {
San Mehatd9a4e352010-03-12 13:32:47 -08001092 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
1093 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
San Mehatb78a32c2010-01-10 13:02:12 -08001094 dmDevice, sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001095 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001096 Loop::destroyByDevice(loopDevice);
1097 return -1;
1098 }
San Mehatd9a4e352010-03-12 13:32:47 -08001099 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001100 SLOGD("New devmapper instance created at %s", dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -08001101 }
San Mehatb78a32c2010-01-10 13:02:12 -08001102 } else {
San Mehatd9a4e352010-03-12 13:32:47 -08001103 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001104 SLOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -08001105 }
San Mehatb78a32c2010-01-10 13:02:12 -08001106 }
1107 cleanupDm = true;
1108 } else {
1109 strcpy(dmDevice, loopDevice);
San Mehata19b2502010-01-06 10:33:53 -08001110 }
1111
Kenny Root344ca102012-04-03 17:23:01 -07001112 if (mkdir(mountPoint, 0000)) {
San Mehatb78a32c2010-01-10 13:02:12 -08001113 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -07001114 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001115 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -08001116 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -08001117 }
1118 Loop::destroyByDevice(loopDevice);
1119 return -1;
1120 }
San Mehata19b2502010-01-06 10:33:53 -08001121 }
1122
Kenny Rootcdc2a1c2012-05-03 13:49:46 -07001123 /*
1124 * The device mapper node needs to be created. Sometimes it takes a
1125 * while. Wait for up to 1 second. We could also inspect incoming uevents,
1126 * but that would take more effort.
1127 */
1128 int tries = 25;
1129 while (tries--) {
1130 if (!access(dmDevice, F_OK) || errno != ENOENT) {
1131 break;
1132 }
1133 usleep(40 * 1000);
1134 }
1135
Kenny Root344ca102012-04-03 17:23:01 -07001136 int result;
1137 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
1138 result = Ext4::doMount(dmDevice, mountPoint, true, false, true);
1139 } else {
1140 result = Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0, 0222, false);
1141 }
1142
1143 if (result) {
San Mehat97ac40e2010-03-24 10:24:19 -07001144 SLOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001145 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -08001146 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -08001147 }
1148 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -08001149 return -1;
1150 }
1151
Kenny Rootcbacf782010-09-24 15:11:48 -07001152 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehatd9a4e352010-03-12 13:32:47 -08001153 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001154 SLOGD("ASEC %s mounted", id);
San Mehatd9a4e352010-03-12 13:32:47 -08001155 }
San Mehata19b2502010-01-06 10:33:53 -08001156 return 0;
1157}
1158
Kenny Root93ecb382012-08-09 11:28:37 -07001159Volume* VolumeManager::getVolumeForFile(const char *fileName) {
1160 VolumeCollection::iterator i;
1161
1162 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
Jeff Sharkeyba6ae8d2013-07-15 18:14:25 -07001163 const char* mountPoint = (*i)->getFuseMountpoint();
Kenny Root93ecb382012-08-09 11:28:37 -07001164 if (!strncmp(fileName, mountPoint, strlen(mountPoint))) {
1165 return *i;
1166 }
1167 }
1168
1169 return NULL;
1170}
1171
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001172/**
1173 * Mounts an image file <code>img</code>.
1174 */
Jeff Sharkey69479042012-09-25 16:14:57 -07001175int VolumeManager::mountObb(const char *img, const char *key, int ownerGid) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001176 char mountPoint[255];
1177
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001178 char idHash[33];
1179 if (!asecHash(img, idHash, sizeof(idHash))) {
1180 SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
1181 return -1;
1182 }
1183
rpcraigd1c226f2012-10-09 06:58:16 -04001184 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
1185 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
Colin Cross59846b62014-02-06 20:34:29 -08001186 SLOGE("OBB mount failed for %s: couldn't construct mountpoint", img);
rpcraigd1c226f2012-10-09 06:58:16 -04001187 return -1;
1188 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001189
1190 if (isMountpointMounted(mountPoint)) {
1191 SLOGE("Image %s already mounted", img);
1192 errno = EBUSY;
1193 return -1;
1194 }
1195
1196 char loopDevice[255];
1197 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
1198 if (Loop::create(idHash, img, loopDevice, sizeof(loopDevice))) {
1199 SLOGE("Image loop device creation failed (%s)", strerror(errno));
1200 return -1;
1201 }
1202 if (mDebug) {
1203 SLOGD("New loop device created at %s", loopDevice);
1204 }
1205 } else {
1206 if (mDebug) {
1207 SLOGD("Found active loopback for %s at %s", img, loopDevice);
1208 }
1209 }
1210
1211 char dmDevice[255];
1212 bool cleanupDm = false;
1213 int fd;
1214 unsigned int nr_sec = 0;
1215
1216 if ((fd = open(loopDevice, O_RDWR)) < 0) {
1217 SLOGE("Failed to open loopdevice (%s)", strerror(errno));
1218 Loop::destroyByDevice(loopDevice);
1219 return -1;
1220 }
1221
1222 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
1223 SLOGE("Failed to get loop size (%s)", strerror(errno));
1224 Loop::destroyByDevice(loopDevice);
1225 close(fd);
1226 return -1;
1227 }
1228
1229 close(fd);
1230
1231 if (strcmp(key, "none")) {
1232 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
1233 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
1234 dmDevice, sizeof(dmDevice))) {
1235 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
1236 Loop::destroyByDevice(loopDevice);
1237 return -1;
1238 }
1239 if (mDebug) {
1240 SLOGD("New devmapper instance created at %s", dmDevice);
1241 }
1242 } else {
1243 if (mDebug) {
1244 SLOGD("Found active devmapper for %s at %s", img, dmDevice);
1245 }
1246 }
1247 cleanupDm = true;
1248 } else {
1249 strcpy(dmDevice, loopDevice);
1250 }
1251
1252 if (mkdir(mountPoint, 0755)) {
1253 if (errno != EEXIST) {
1254 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
1255 if (cleanupDm) {
1256 Devmapper::destroy(idHash);
1257 }
1258 Loop::destroyByDevice(loopDevice);
1259 return -1;
1260 }
1261 }
1262
Jeff Sharkey69479042012-09-25 16:14:57 -07001263 if (Fat::doMount(dmDevice, mountPoint, true, false, true, 0, ownerGid,
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001264 0227, false)) {
1265 SLOGE("Image mount failed (%s)", strerror(errno));
1266 if (cleanupDm) {
1267 Devmapper::destroy(idHash);
1268 }
1269 Loop::destroyByDevice(loopDevice);
1270 return -1;
1271 }
1272
Kenny Rootcbacf782010-09-24 15:11:48 -07001273 mActiveContainers->push_back(new ContainerData(strdup(img), OBB));
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001274 if (mDebug) {
1275 SLOGD("Image %s mounted", img);
1276 }
1277 return 0;
1278}
1279
San Mehat49e2bce2009-10-12 16:29:01 -07001280int VolumeManager::mountVolume(const char *label) {
1281 Volume *v = lookupVolume(label);
1282
1283 if (!v) {
1284 errno = ENOENT;
1285 return -1;
1286 }
1287
San Mehata2677e42009-12-13 10:40:18 -08001288 return v->mountVol();
1289}
1290
Kenny Root508c0e12010-07-12 09:59:49 -07001291int VolumeManager::listMountedObbs(SocketClient* cli) {
1292 char device[256];
1293 char mount_path[256];
1294 char rest[256];
1295 FILE *fp;
1296 char line[1024];
1297
1298 if (!(fp = fopen("/proc/mounts", "r"))) {
1299 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
1300 return -1;
1301 }
1302
1303 // Create a string to compare against that has a trailing slash
Kenny Root93ecb382012-08-09 11:28:37 -07001304 int loopDirLen = strlen(Volume::LOOPDIR);
Kenny Root508c0e12010-07-12 09:59:49 -07001305 char loopDir[loopDirLen + 2];
1306 strcpy(loopDir, Volume::LOOPDIR);
1307 loopDir[loopDirLen++] = '/';
1308 loopDir[loopDirLen] = '\0';
1309
1310 while(fgets(line, sizeof(line), fp)) {
1311 line[strlen(line)-1] = '\0';
1312
1313 /*
1314 * Should look like:
1315 * /dev/block/loop0 /mnt/obb/fc99df1323fd36424f864dcb76b76d65 ...
1316 */
1317 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1318
1319 if (!strncmp(mount_path, loopDir, loopDirLen)) {
1320 int fd = open(device, O_RDONLY);
1321 if (fd >= 0) {
1322 struct loop_info64 li;
1323 if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
1324 cli->sendMsg(ResponseCode::AsecListResult,
1325 (const char*) li.lo_file_name, false);
1326 }
1327 close(fd);
1328 }
1329 }
1330 }
1331
1332 fclose(fp);
1333 return 0;
1334}
1335
San Mehateba65e92010-01-29 05:15:16 -08001336int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
1337 Volume *v = lookupVolume(label);
1338
1339 if (!v) {
1340 errno = ENOENT;
1341 return -1;
1342 }
1343
1344 if (strcmp(method, "ums")) {
1345 errno = ENOSYS;
1346 return -1;
1347 }
1348
1349 if (v->getState() != Volume::State_Shared) {
San Mehateba65e92010-01-29 05:15:16 -08001350 *enabled = false;
San Mehatb9aed742010-02-04 15:07:01 -08001351 } else {
1352 *enabled = true;
San Mehateba65e92010-01-29 05:15:16 -08001353 }
1354 return 0;
1355}
1356
San Mehata2677e42009-12-13 10:40:18 -08001357int VolumeManager::shareVolume(const char *label, const char *method) {
1358 Volume *v = lookupVolume(label);
1359
1360 if (!v) {
1361 errno = ENOENT;
1362 return -1;
1363 }
1364
1365 /*
1366 * Eventually, we'll want to support additional share back-ends,
1367 * some of which may work while the media is mounted. For now,
1368 * we just support UMS
1369 */
1370 if (strcmp(method, "ums")) {
1371 errno = ENOSYS;
1372 return -1;
1373 }
1374
1375 if (v->getState() == Volume::State_NoMedia) {
1376 errno = ENODEV;
1377 return -1;
1378 }
1379
San Mehat49e2bce2009-10-12 16:29:01 -07001380 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -08001381 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -07001382 errno = EBUSY;
1383 return -1;
1384 }
1385
Ken Sumrall3b170052011-07-11 15:38:57 -07001386 if (mVolManagerDisabled) {
1387 errno = EBUSY;
1388 return -1;
1389 }
1390
Mike Lockwood2dfe2972010-09-17 18:50:51 -04001391 dev_t d = v->getShareDevice();
San Mehata2677e42009-12-13 10:40:18 -08001392 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
1393 // This volume does not support raw disk access
1394 errno = EINVAL;
1395 return -1;
1396 }
1397
1398 int fd;
1399 char nodepath[255];
rpcraigd1c226f2012-10-09 06:58:16 -04001400 int written = snprintf(nodepath,
San Mehata2677e42009-12-13 10:40:18 -08001401 sizeof(nodepath), "/dev/block/vold/%d:%d",
Colin Cross346c5b22014-01-22 23:59:41 -08001402 major(d), minor(d));
San Mehata2677e42009-12-13 10:40:18 -08001403
rpcraigd1c226f2012-10-09 06:58:16 -04001404 if ((written < 0) || (size_t(written) >= sizeof(nodepath))) {
1405 SLOGE("shareVolume failed: couldn't construct nodepath");
1406 return -1;
1407 }
1408
Mike Lockwood97f2fc12011-06-07 10:51:38 -07001409 if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001410 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001411 return -1;
1412 }
1413
1414 if (write(fd, nodepath, strlen(nodepath)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001415 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001416 close(fd);
1417 return -1;
1418 }
1419
1420 close(fd);
1421 v->handleVolumeShared();
Mike Lockwooda28056b2010-10-28 15:21:24 -04001422 if (mUmsSharingCount++ == 0) {
1423 FILE* fp;
1424 mSavedDirtyRatio = -1; // in case we fail
1425 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1426 char line[16];
1427 if (fgets(line, sizeof(line), fp) && sscanf(line, "%d", &mSavedDirtyRatio)) {
1428 fprintf(fp, "%d\n", mUmsDirtyRatio);
1429 } else {
1430 SLOGE("Failed to read dirty_ratio (%s)", strerror(errno));
1431 }
1432 fclose(fp);
1433 } else {
1434 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1435 }
1436 }
San Mehata2677e42009-12-13 10:40:18 -08001437 return 0;
1438}
1439
1440int VolumeManager::unshareVolume(const char *label, const char *method) {
1441 Volume *v = lookupVolume(label);
1442
1443 if (!v) {
1444 errno = ENOENT;
1445 return -1;
1446 }
1447
1448 if (strcmp(method, "ums")) {
1449 errno = ENOSYS;
1450 return -1;
1451 }
1452
1453 if (v->getState() != Volume::State_Shared) {
1454 errno = EINVAL;
1455 return -1;
1456 }
1457
San Mehata2677e42009-12-13 10:40:18 -08001458 int fd;
Mike Lockwood97f2fc12011-06-07 10:51:38 -07001459 if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001460 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001461 return -1;
1462 }
1463
1464 char ch = 0;
1465 if (write(fd, &ch, 1) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001466 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001467 close(fd);
1468 return -1;
1469 }
1470
1471 close(fd);
1472 v->handleVolumeUnshared();
Mike Lockwooda28056b2010-10-28 15:21:24 -04001473 if (--mUmsSharingCount == 0 && mSavedDirtyRatio != -1) {
1474 FILE* fp;
1475 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1476 fprintf(fp, "%d\n", mSavedDirtyRatio);
1477 fclose(fp);
1478 } else {
1479 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1480 }
1481 mSavedDirtyRatio = -1;
1482 }
San Mehata2677e42009-12-13 10:40:18 -08001483 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -07001484}
1485
Ken Sumrall3b170052011-07-11 15:38:57 -07001486extern "C" int vold_disableVol(const char *label) {
Ken Sumrall29d8da82011-05-18 17:20:07 -07001487 VolumeManager *vm = VolumeManager::Instance();
Ken Sumrall3b170052011-07-11 15:38:57 -07001488 vm->disableVolumeManager();
1489 vm->unshareVolume(label, "ums");
Ken Sumrall0b8b5972011-08-31 16:14:23 -07001490 return vm->unmountVolume(label, true, false);
Ken Sumrall29d8da82011-05-18 17:20:07 -07001491}
1492
1493extern "C" int vold_getNumDirectVolumes(void) {
1494 VolumeManager *vm = VolumeManager::Instance();
1495 return vm->getNumDirectVolumes();
1496}
1497
1498int VolumeManager::getNumDirectVolumes(void) {
1499 VolumeCollection::iterator i;
1500 int n=0;
1501
1502 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1503 if ((*i)->getShareDevice() != (dev_t)0) {
1504 n++;
1505 }
1506 }
1507 return n;
1508}
1509
1510extern "C" int vold_getDirectVolumeList(struct volume_info *vol_list) {
1511 VolumeManager *vm = VolumeManager::Instance();
1512 return vm->getDirectVolumeList(vol_list);
1513}
1514
1515int VolumeManager::getDirectVolumeList(struct volume_info *vol_list) {
1516 VolumeCollection::iterator i;
1517 int n=0;
1518 dev_t d;
1519
1520 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1521 if ((d=(*i)->getShareDevice()) != (dev_t)0) {
1522 (*i)->getVolInfo(&vol_list[n]);
1523 snprintf(vol_list[n].blk_dev, sizeof(vol_list[n].blk_dev),
Colin Cross346c5b22014-01-22 23:59:41 -08001524 "/dev/block/vold/%d:%d", major(d), minor(d));
Ken Sumrall29d8da82011-05-18 17:20:07 -07001525 n++;
1526 }
1527 }
1528
1529 return 0;
1530}
1531
Ken Sumrall0b8b5972011-08-31 16:14:23 -07001532int VolumeManager::unmountVolume(const char *label, bool force, bool revert) {
San Mehat49e2bce2009-10-12 16:29:01 -07001533 Volume *v = lookupVolume(label);
1534
1535 if (!v) {
1536 errno = ENOENT;
1537 return -1;
1538 }
1539
San Mehata2677e42009-12-13 10:40:18 -08001540 if (v->getState() == Volume::State_NoMedia) {
1541 errno = ENODEV;
1542 return -1;
1543 }
1544
San Mehat49e2bce2009-10-12 16:29:01 -07001545 if (v->getState() != Volume::State_Mounted) {
San Mehat97ac40e2010-03-24 10:24:19 -07001546 SLOGW("Attempt to unmount volume which isn't mounted (%d)\n",
San Mehata2677e42009-12-13 10:40:18 -08001547 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -07001548 errno = EBUSY;
Ken Sumrall319b1042011-06-14 14:01:55 -07001549 return UNMOUNT_NOT_MOUNTED_ERR;
San Mehat49e2bce2009-10-12 16:29:01 -07001550 }
1551
San Mehat1a06eda2010-04-15 12:58:50 -07001552 cleanupAsec(v, force);
San Mehat88705162010-01-15 09:26:28 -08001553
Ken Sumrall0b8b5972011-08-31 16:14:23 -07001554 return v->unmountVol(force, revert);
San Mehat49e2bce2009-10-12 16:29:01 -07001555}
1556
Ken Sumrall425524d2012-06-14 20:55:28 -07001557extern "C" int vold_unmountAllAsecs(void) {
1558 int rc;
1559
1560 VolumeManager *vm = VolumeManager::Instance();
1561 rc = vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_EXT);
1562 if (vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_INT)) {
1563 rc = -1;
1564 }
1565 return rc;
1566}
1567
1568#define ID_BUF_LEN 256
1569#define ASEC_SUFFIX ".asec"
1570#define ASEC_SUFFIX_LEN (sizeof(ASEC_SUFFIX) - 1)
1571int VolumeManager::unmountAllAsecsInDir(const char *directory) {
1572 DIR *d = opendir(directory);
1573 int rc = 0;
1574
1575 if (!d) {
1576 SLOGE("Could not open asec dir %s", directory);
1577 return -1;
1578 }
1579
1580 size_t dirent_len = offsetof(struct dirent, d_name) +
Elliott Hughes8c480f72012-10-26 16:57:19 -07001581 fpathconf(dirfd(d), _PC_NAME_MAX) + 1;
Ken Sumrall425524d2012-06-14 20:55:28 -07001582
1583 struct dirent *dent = (struct dirent *) malloc(dirent_len);
1584 if (dent == NULL) {
1585 SLOGE("Failed to allocate memory for asec dir");
1586 return -1;
1587 }
1588
1589 struct dirent *result;
1590 while (!readdir_r(d, dent, &result) && result != NULL) {
1591 if (dent->d_name[0] == '.')
1592 continue;
1593 if (dent->d_type != DT_REG)
1594 continue;
1595 size_t name_len = strlen(dent->d_name);
1596 if (name_len > 5 && name_len < (ID_BUF_LEN + ASEC_SUFFIX_LEN - 1) &&
1597 !strcmp(&dent->d_name[name_len - 5], ASEC_SUFFIX)) {
1598 char id[ID_BUF_LEN];
1599 strlcpy(id, dent->d_name, name_len - 4);
1600 if (unmountAsec(id, true)) {
1601 /* Register the error, but try to unmount more asecs */
1602 rc = -1;
1603 }
1604 }
1605 }
1606 closedir(d);
1607
1608 free(dent);
1609
1610 return rc;
1611}
1612
San Mehata2677e42009-12-13 10:40:18 -08001613/*
1614 * Looks up a volume by it's label or mount-point
1615 */
San Mehat49e2bce2009-10-12 16:29:01 -07001616Volume *VolumeManager::lookupVolume(const char *label) {
1617 VolumeCollection::iterator i;
1618
1619 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -08001620 if (label[0] == '/') {
Jeff Sharkeyba6ae8d2013-07-15 18:14:25 -07001621 if (!strcmp(label, (*i)->getFuseMountpoint()))
San Mehata2677e42009-12-13 10:40:18 -08001622 return (*i);
1623 } else {
1624 if (!strcmp(label, (*i)->getLabel()))
1625 return (*i);
1626 }
San Mehat49e2bce2009-10-12 16:29:01 -07001627 }
1628 return NULL;
1629}
San Mehata19b2502010-01-06 10:33:53 -08001630
1631bool VolumeManager::isMountpointMounted(const char *mp)
1632{
1633 char device[256];
1634 char mount_path[256];
1635 char rest[256];
1636 FILE *fp;
1637 char line[1024];
1638
1639 if (!(fp = fopen("/proc/mounts", "r"))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001640 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001641 return false;
1642 }
1643
1644 while(fgets(line, sizeof(line), fp)) {
1645 line[strlen(line)-1] = '\0';
1646 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1647 if (!strcmp(mount_path, mp)) {
1648 fclose(fp);
1649 return true;
1650 }
San Mehata19b2502010-01-06 10:33:53 -08001651 }
1652
1653 fclose(fp);
1654 return false;
1655}
1656
San Mehat1a06eda2010-04-15 12:58:50 -07001657int VolumeManager::cleanupAsec(Volume *v, bool force) {
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001658 int rc = 0;
Kenny Root93ecb382012-08-09 11:28:37 -07001659
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001660 char asecFileName[255];
1661
1662 AsecIdCollection removeAsec;
1663 AsecIdCollection removeObb;
1664
Kenny Root93ecb382012-08-09 11:28:37 -07001665 for (AsecIdCollection::iterator it = mActiveContainers->begin(); it != mActiveContainers->end();
1666 ++it) {
Kenny Rootcbacf782010-09-24 15:11:48 -07001667 ContainerData* cd = *it;
Kenny Root93ecb382012-08-09 11:28:37 -07001668
Kenny Rootcbacf782010-09-24 15:11:48 -07001669 if (cd->type == ASEC) {
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001670 if (findAsec(cd->id, asecFileName, sizeof(asecFileName))) {
1671 SLOGE("Couldn't find ASEC %s; cleaning up", cd->id);
1672 removeAsec.push_back(cd);
1673 } else {
1674 SLOGD("Found ASEC at path %s", asecFileName);
1675 if (!strncmp(asecFileName, Volume::SEC_ASECDIR_EXT,
1676 strlen(Volume::SEC_ASECDIR_EXT))) {
1677 removeAsec.push_back(cd);
1678 }
1679 }
Kenny Rootcbacf782010-09-24 15:11:48 -07001680 } else if (cd->type == OBB) {
Kenny Root93ecb382012-08-09 11:28:37 -07001681 if (v == getVolumeForFile(cd->id)) {
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001682 removeObb.push_back(cd);
Kenny Rootcbacf782010-09-24 15:11:48 -07001683 }
1684 } else {
1685 SLOGE("Unknown container type %d!", cd->type);
San Mehat1a06eda2010-04-15 12:58:50 -07001686 }
1687 }
Kenny Root93ecb382012-08-09 11:28:37 -07001688
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001689 for (AsecIdCollection::iterator it = removeAsec.begin(); it != removeAsec.end(); ++it) {
Kenny Root93ecb382012-08-09 11:28:37 -07001690 ContainerData *cd = *it;
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001691 SLOGI("Unmounting ASEC %s (dependent on %s)", cd->id, v->getLabel());
1692 if (unmountAsec(cd->id, force)) {
1693 SLOGE("Failed to unmount ASEC %s (%s)", cd->id, strerror(errno));
1694 rc = -1;
1695 }
1696 }
1697
1698 for (AsecIdCollection::iterator it = removeObb.begin(); it != removeObb.end(); ++it) {
1699 ContainerData *cd = *it;
1700 SLOGI("Unmounting OBB %s (dependent on %s)", cd->id, v->getLabel());
Kenny Root93ecb382012-08-09 11:28:37 -07001701 if (unmountObb(cd->id, force)) {
1702 SLOGE("Failed to unmount OBB %s (%s)", cd->id, strerror(errno));
1703 rc = -1;
1704 }
1705 }
1706
1707 return rc;
San Mehat1a06eda2010-04-15 12:58:50 -07001708}
1709
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001710int VolumeManager::mkdirs(char* path) {
1711 // Require that path lives under a volume we manage
1712 const char* emulated_source = getenv("EMULATED_STORAGE_SOURCE");
1713 const char* root = NULL;
Marco Nelissen5ab02e72013-10-15 15:22:28 -07001714 if (emulated_source && !strncmp(path, emulated_source, strlen(emulated_source))) {
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001715 root = emulated_source;
1716 } else {
1717 Volume* vol = getVolumeForFile(path);
1718 if (vol) {
1719 root = vol->getMountpoint();
1720 }
1721 }
1722
1723 if (!root) {
1724 SLOGE("Failed to find volume for %s", path);
1725 return -EINVAL;
1726 }
1727
1728 /* fs_mkdirs() does symlink checking and relative path enforcement */
1729 return fs_mkdirs(path, 0700);
1730}