blob: 2a9cd20f12d1bd526eb4740537d9d3c7879edca8 [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
San Mehatfd7f5872009-10-12 11:32:47 -070038#include <sysutils/NetlinkEvent.h>
39
Kenny Root344ca102012-04-03 17:23:01 -070040#include <private/android_filesystem_config.h>
41
San Mehatf1b736b2009-10-10 17:22:08 -070042#include "VolumeManager.h"
San Mehatae10b912009-10-12 14:57:05 -070043#include "DirectVolume.h"
San Mehata2677e42009-12-13 10:40:18 -080044#include "ResponseCode.h"
San Mehata19b2502010-01-06 10:33:53 -080045#include "Loop.h"
Kenny Root344ca102012-04-03 17:23:01 -070046#include "Ext4.h"
San Mehata19b2502010-01-06 10:33:53 -080047#include "Fat.h"
San Mehatb78a32c2010-01-10 13:02:12 -080048#include "Devmapper.h"
San Mehat586536c2010-02-16 17:12:00 -080049#include "Process.h"
San Mehatfcf24fe2010-03-03 12:37:32 -080050#include "Asec.h"
Ken Sumrall29d8da82011-05-18 17:20:07 -070051#include "cryptfs.h"
San Mehat23969932010-01-09 07:08:06 -080052
Mike Lockwood97f2fc12011-06-07 10:51:38 -070053#define MASS_STORAGE_FILE_PATH "/sys/class/android_usb/android0/f_mass_storage/lun/file"
54
San Mehatf1b736b2009-10-10 17:22:08 -070055VolumeManager *VolumeManager::sInstance = NULL;
56
57VolumeManager *VolumeManager::Instance() {
58 if (!sInstance)
59 sInstance = new VolumeManager();
60 return sInstance;
61}
62
63VolumeManager::VolumeManager() {
San Mehatd9a4e352010-03-12 13:32:47 -080064 mDebug = false;
San Mehatf1b736b2009-10-10 17:22:08 -070065 mVolumes = new VolumeCollection();
San Mehat88705162010-01-15 09:26:28 -080066 mActiveContainers = new AsecIdCollection();
San Mehatf1b736b2009-10-10 17:22:08 -070067 mBroadcaster = NULL;
Mike Lockwooda28056b2010-10-28 15:21:24 -040068 mUmsSharingCount = 0;
69 mSavedDirtyRatio = -1;
70 // set dirty ratio to 0 when UMS is active
71 mUmsDirtyRatio = 0;
Ken Sumrall3b170052011-07-11 15:38:57 -070072 mVolManagerDisabled = 0;
San Mehatf1b736b2009-10-10 17:22:08 -070073}
74
75VolumeManager::~VolumeManager() {
San Mehat88705162010-01-15 09:26:28 -080076 delete mVolumes;
77 delete mActiveContainers;
San Mehatf1b736b2009-10-10 17:22:08 -070078}
79
Kenny Root7b18a7b2010-03-15 13:13:41 -070080char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -070081 static const char* digits = "0123456789abcdef";
82
Kenny Root7b18a7b2010-03-15 13:13:41 -070083 unsigned char sig[MD5_DIGEST_LENGTH];
84
Kenny Rootacc9e7d2010-06-18 19:06:50 -070085 if (buffer == NULL) {
86 SLOGE("Destination buffer is NULL");
87 errno = ESPIPE;
88 return NULL;
89 } else if (id == NULL) {
90 SLOGE("Source buffer is NULL");
91 errno = ESPIPE;
92 return NULL;
93 } else if (len < MD5_ASCII_LENGTH_PLUS_NULL) {
94 SLOGE("Target hash buffer size < %d bytes (%d)",
95 MD5_ASCII_LENGTH_PLUS_NULL, len);
San Mehatd9a4e352010-03-12 13:32:47 -080096 errno = ESPIPE;
97 return NULL;
98 }
Kenny Root7b18a7b2010-03-15 13:13:41 -070099
100 MD5(reinterpret_cast<const unsigned char*>(id), strlen(id), sig);
San Mehatd9a4e352010-03-12 13:32:47 -0800101
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700102 char *p = buffer;
Kenny Root7b18a7b2010-03-15 13:13:41 -0700103 for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700104 *p++ = digits[sig[i] >> 4];
105 *p++ = digits[sig[i] & 0x0F];
San Mehatd9a4e352010-03-12 13:32:47 -0800106 }
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700107 *p = '\0';
San Mehatd9a4e352010-03-12 13:32:47 -0800108
109 return buffer;
110}
111
112void VolumeManager::setDebug(bool enable) {
113 mDebug = enable;
114 VolumeCollection::iterator it;
115 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
116 (*it)->setDebug(enable);
117 }
118}
119
San Mehatf1b736b2009-10-10 17:22:08 -0700120int VolumeManager::start() {
121 return 0;
122}
123
124int VolumeManager::stop() {
125 return 0;
126}
127
128int VolumeManager::addVolume(Volume *v) {
129 mVolumes->push_back(v);
130 return 0;
131}
132
San Mehatfd7f5872009-10-12 11:32:47 -0700133void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
134 const char *devpath = evt->findParam("DEVPATH");
San Mehatf1b736b2009-10-10 17:22:08 -0700135
San Mehatfd7f5872009-10-12 11:32:47 -0700136 /* Lookup a volume to handle this device */
San Mehatf1b736b2009-10-10 17:22:08 -0700137 VolumeCollection::iterator it;
138 bool hit = false;
139 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
San Mehatfd7f5872009-10-12 11:32:47 -0700140 if (!(*it)->handleBlockEvent(evt)) {
San Mehata2677e42009-12-13 10:40:18 -0800141#ifdef NETLINK_DEBUG
San Mehat97ac40e2010-03-24 10:24:19 -0700142 SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
San Mehata2677e42009-12-13 10:40:18 -0800143#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700144 hit = true;
San Mehatf1b736b2009-10-10 17:22:08 -0700145 break;
146 }
147 }
148
149 if (!hit) {
San Mehata2677e42009-12-13 10:40:18 -0800150#ifdef NETLINK_DEBUG
San Mehat97ac40e2010-03-24 10:24:19 -0700151 SLOGW("No volumes handled block event for '%s'", devpath);
San Mehata2677e42009-12-13 10:40:18 -0800152#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700153 }
154}
155
San Mehatf1b736b2009-10-10 17:22:08 -0700156int VolumeManager::listVolumes(SocketClient *cli) {
157 VolumeCollection::iterator i;
158
159 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
160 char *buffer;
161 asprintf(&buffer, "%s %s %d",
Jeff Sharkeyba6ae8d2013-07-15 18:14:25 -0700162 (*i)->getLabel(), (*i)->getFuseMountpoint(),
San Mehatf1b736b2009-10-10 17:22:08 -0700163 (*i)->getState());
San Mehata2677e42009-12-13 10:40:18 -0800164 cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
San Mehatf1b736b2009-10-10 17:22:08 -0700165 free(buffer);
166 }
San Mehata2677e42009-12-13 10:40:18 -0800167 cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
San Mehatf1b736b2009-10-10 17:22:08 -0700168 return 0;
169}
San Mehat49e2bce2009-10-12 16:29:01 -0700170
Ken Sumrall9caab762013-06-11 19:10:20 -0700171int VolumeManager::formatVolume(const char *label, bool wipe) {
San Mehata2677e42009-12-13 10:40:18 -0800172 Volume *v = lookupVolume(label);
173
174 if (!v) {
175 errno = ENOENT;
176 return -1;
177 }
178
Ken Sumrall3b170052011-07-11 15:38:57 -0700179 if (mVolManagerDisabled) {
180 errno = EBUSY;
181 return -1;
182 }
183
Ken Sumrall9caab762013-06-11 19:10:20 -0700184 return v->formatVol(wipe);
San Mehata2677e42009-12-13 10:40:18 -0800185}
186
Kenny Root508c0e12010-07-12 09:59:49 -0700187int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) {
188 char idHash[33];
189 if (!asecHash(sourceFile, idHash, sizeof(idHash))) {
190 SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno));
191 return -1;
192 }
193
194 memset(mountPath, 0, mountPathLen);
rpcraigd1c226f2012-10-09 06:58:16 -0400195 int written = snprintf(mountPath, mountPathLen, "%s/%s", Volume::LOOPDIR, idHash);
196 if ((written < 0) || (written >= mountPathLen)) {
197 errno = EINVAL;
198 return -1;
199 }
Kenny Root508c0e12010-07-12 09:59:49 -0700200
201 if (access(mountPath, F_OK)) {
202 errno = ENOENT;
203 return -1;
204 }
205
206 return 0;
207}
208
San Mehata19b2502010-01-06 10:33:53 -0800209int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
San Mehat88ac2c02010-03-23 11:15:58 -0700210 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700211
212 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
213 SLOGE("Couldn't find ASEC %s", id);
214 return -1;
215 }
San Mehat88ac2c02010-03-23 11:15:58 -0700216
217 memset(buffer, 0, maxlen);
218 if (access(asecFileName, F_OK)) {
219 errno = ENOENT;
220 return -1;
221 }
San Mehata19b2502010-01-06 10:33:53 -0800222
rpcraigd1c226f2012-10-09 06:58:16 -0400223 int written = snprintf(buffer, maxlen, "%s/%s", Volume::ASECDIR, id);
224 if ((written < 0) || (written >= maxlen)) {
225 SLOGE("getAsecMountPath failed for %s: couldn't construct path in buffer", id);
226 errno = EINVAL;
227 return -1;
228 }
229
San Mehata19b2502010-01-06 10:33:53 -0800230 return 0;
231}
232
Dianne Hackborn736910c2011-06-27 13:37:07 -0700233int VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxlen) {
234 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700235
236 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
237 SLOGE("Couldn't find ASEC %s", id);
238 return -1;
239 }
Dianne Hackborn736910c2011-06-27 13:37:07 -0700240
241 memset(buffer, 0, maxlen);
242 if (access(asecFileName, F_OK)) {
243 errno = ENOENT;
244 return -1;
245 }
246
rpcraigd1c226f2012-10-09 06:58:16 -0400247 int written = snprintf(buffer, maxlen, "%s", asecFileName);
248 if ((written < 0) || (written >= maxlen)) {
249 errno = EINVAL;
250 return -1;
251 }
252
Dianne Hackborn736910c2011-06-27 13:37:07 -0700253 return 0;
254}
255
Kenny Root344ca102012-04-03 17:23:01 -0700256int VolumeManager::createAsec(const char *id, unsigned int numSectors, const char *fstype,
257 const char *key, const int ownerUid, bool isExternal) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800258 struct asec_superblock sb;
259 memset(&sb, 0, sizeof(sb));
260
Kenny Root344ca102012-04-03 17:23:01 -0700261 const bool wantFilesystem = strcmp(fstype, "none");
262 bool usingExt4 = false;
263 if (wantFilesystem) {
264 usingExt4 = !strcmp(fstype, "ext4");
265 if (usingExt4) {
266 sb.c_opts |= ASEC_SB_C_OPTS_EXT4;
267 } else if (strcmp(fstype, "fat")) {
268 SLOGE("Invalid filesystem type %s", fstype);
269 errno = EINVAL;
270 return -1;
271 }
272 }
273
San Mehatfcf24fe2010-03-03 12:37:32 -0800274 sb.magic = ASEC_SB_MAGIC;
275 sb.ver = ASEC_SB_VER;
San Mehata19b2502010-01-06 10:33:53 -0800276
San Mehatd31e3802010-02-18 08:37:45 -0800277 if (numSectors < ((1024*1024)/512)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700278 SLOGE("Invalid container size specified (%d sectors)", numSectors);
San Mehatd31e3802010-02-18 08:37:45 -0800279 errno = EINVAL;
280 return -1;
281 }
282
San Mehata19b2502010-01-06 10:33:53 -0800283 if (lookupVolume(id)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700284 SLOGE("ASEC id '%s' currently exists", id);
San Mehata19b2502010-01-06 10:33:53 -0800285 errno = EADDRINUSE;
286 return -1;
287 }
288
289 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700290
291 if (!findAsec(id, asecFileName, sizeof(asecFileName))) {
292 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
293 asecFileName, strerror(errno));
294 errno = EADDRINUSE;
295 return -1;
296 }
297
298 const char *asecDir = isExternal ? Volume::SEC_ASECDIR_EXT : Volume::SEC_ASECDIR_INT;
299
rpcraigd1c226f2012-10-09 06:58:16 -0400300 int written = snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", asecDir, id);
301 if ((written < 0) || (size_t(written) >= sizeof(asecFileName))) {
302 errno = EINVAL;
303 return -1;
304 }
San Mehata19b2502010-01-06 10:33:53 -0800305
306 if (!access(asecFileName, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700307 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
Kenny Root344ca102012-04-03 17:23:01 -0700308 asecFileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800309 errno = EADDRINUSE;
310 return -1;
311 }
312
San Mehatfcf24fe2010-03-03 12:37:32 -0800313 /*
314 * Add some headroom
315 */
316 unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
317 unsigned numImgSectors = numSectors + fatSize + 2;
318
319 if (numImgSectors % 63) {
320 numImgSectors += (63 - (numImgSectors % 63));
321 }
322
323 // Add +1 for our superblock which is at the end
324 if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700325 SLOGE("ASEC image file creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800326 return -1;
327 }
328
San Mehatd9a4e352010-03-12 13:32:47 -0800329 char idHash[33];
330 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700331 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800332 unlink(asecFileName);
333 return -1;
334 }
335
San Mehata19b2502010-01-06 10:33:53 -0800336 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800337 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700338 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800339 unlink(asecFileName);
340 return -1;
341 }
342
San Mehatb78a32c2010-01-10 13:02:12 -0800343 char dmDevice[255];
344 bool cleanupDm = false;
San Mehata19b2502010-01-06 10:33:53 -0800345
San Mehatb78a32c2010-01-10 13:02:12 -0800346 if (strcmp(key, "none")) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800347 // XXX: This is all we support for now
348 sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
San Mehatd9a4e352010-03-12 13:32:47 -0800349 if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
San Mehatb78a32c2010-01-10 13:02:12 -0800350 sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700351 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800352 Loop::destroyByDevice(loopDevice);
353 unlink(asecFileName);
354 return -1;
355 }
356 cleanupDm = true;
357 } else {
San Mehatfcf24fe2010-03-03 12:37:32 -0800358 sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
San Mehatb78a32c2010-01-10 13:02:12 -0800359 strcpy(dmDevice, loopDevice);
360 }
361
San Mehatfcf24fe2010-03-03 12:37:32 -0800362 /*
363 * Drop down the superblock at the end of the file
364 */
365
366 int sbfd = open(loopDevice, O_RDWR);
367 if (sbfd < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -0700368 SLOGE("Failed to open new DM device for superblock write (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800369 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800370 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800371 }
372 Loop::destroyByDevice(loopDevice);
373 unlink(asecFileName);
374 return -1;
375 }
376
377 if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
378 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700379 SLOGE("Failed to lseek for superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800380 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800381 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800382 }
383 Loop::destroyByDevice(loopDevice);
384 unlink(asecFileName);
385 return -1;
386 }
387
388 if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) {
389 close(sbfd);
San Mehat97ac40e2010-03-24 10:24:19 -0700390 SLOGE("Failed to write superblock (%s)", strerror(errno));
San Mehatfcf24fe2010-03-03 12:37:32 -0800391 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800392 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800393 }
394 Loop::destroyByDevice(loopDevice);
395 unlink(asecFileName);
396 return -1;
397 }
398 close(sbfd);
399
Kenny Root344ca102012-04-03 17:23:01 -0700400 if (wantFilesystem) {
401 int formatStatus;
rpcraiga54e13a2012-09-21 14:17:08 -0400402 char mountPoint[255];
403
rpcraigd1c226f2012-10-09 06:58:16 -0400404 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
405 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
406 SLOGE("ASEC fs format failed: couldn't construct mountPoint");
407 if (cleanupDm) {
408 Devmapper::destroy(idHash);
409 }
410 Loop::destroyByDevice(loopDevice);
411 unlink(asecFileName);
412 return -1;
413 }
rpcraiga54e13a2012-09-21 14:17:08 -0400414
Kenny Root344ca102012-04-03 17:23:01 -0700415 if (usingExt4) {
rpcraiga54e13a2012-09-21 14:17:08 -0400416 formatStatus = Ext4::format(dmDevice, mountPoint);
Kenny Root344ca102012-04-03 17:23:01 -0700417 } else {
Ken Sumrall9caab762013-06-11 19:10:20 -0700418 formatStatus = Fat::format(dmDevice, numImgSectors, 0);
San Mehatb78a32c2010-01-10 13:02:12 -0800419 }
San Mehata19b2502010-01-06 10:33:53 -0800420
Kenny Root344ca102012-04-03 17:23:01 -0700421 if (formatStatus < 0) {
422 SLOGE("ASEC fs format failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800423 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800424 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800425 }
San Mehateb13a902010-01-07 12:12:50 -0800426 Loop::destroyByDevice(loopDevice);
427 unlink(asecFileName);
428 return -1;
429 }
Kenny Root344ca102012-04-03 17:23:01 -0700430
Kenny Root344ca102012-04-03 17:23:01 -0700431 if (mkdir(mountPoint, 0000)) {
San Mehata1091cb2010-02-28 20:17:20 -0800432 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -0700433 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800434 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800435 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800436 }
437 Loop::destroyByDevice(loopDevice);
438 unlink(asecFileName);
439 return -1;
440 }
San Mehatb78a32c2010-01-10 13:02:12 -0800441 }
San Mehata1091cb2010-02-28 20:17:20 -0800442
Kenny Root344ca102012-04-03 17:23:01 -0700443 int mountStatus;
444 if (usingExt4) {
445 mountStatus = Ext4::doMount(dmDevice, mountPoint, false, false, false);
446 } else {
447 mountStatus = Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid, 0, 0000,
448 false);
449 }
450
451 if (mountStatus) {
San Mehat97ac40e2010-03-24 10:24:19 -0700452 SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800453 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800454 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800455 }
456 Loop::destroyByDevice(loopDevice);
457 unlink(asecFileName);
458 return -1;
459 }
Kenny Root344ca102012-04-03 17:23:01 -0700460
461 if (usingExt4) {
462 int dirfd = open(mountPoint, O_DIRECTORY);
463 if (dirfd >= 0) {
464 if (fchown(dirfd, ownerUid, AID_SYSTEM)
465 || fchmod(dirfd, S_IRUSR | S_IWUSR | S_IXUSR | S_ISGID | S_IRGRP | S_IXGRP)) {
466 SLOGI("Cannot chown/chmod new ASEC mount point %s", mountPoint);
467 }
468 close(dirfd);
469 }
470 }
San Mehata1091cb2010-02-28 20:17:20 -0800471 } else {
San Mehat97ac40e2010-03-24 10:24:19 -0700472 SLOGI("Created raw secure container %s (no filesystem)", id);
San Mehata19b2502010-01-06 10:33:53 -0800473 }
San Mehat88705162010-01-15 09:26:28 -0800474
Kenny Rootcbacf782010-09-24 15:11:48 -0700475 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehata19b2502010-01-06 10:33:53 -0800476 return 0;
477}
478
479int VolumeManager::finalizeAsec(const char *id) {
480 char asecFileName[255];
481 char loopDevice[255];
482 char mountPoint[255];
483
Kenny Root344ca102012-04-03 17:23:01 -0700484 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
485 SLOGE("Couldn't find ASEC %s", id);
486 return -1;
487 }
San Mehata19b2502010-01-06 10:33:53 -0800488
San Mehatd9a4e352010-03-12 13:32:47 -0800489 char idHash[33];
490 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700491 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800492 return -1;
493 }
494
495 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700496 SLOGE("Unable to finalize %s (%s)", id, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800497 return -1;
498 }
499
Kenny Root344ca102012-04-03 17:23:01 -0700500 unsigned int nr_sec = 0;
501 struct asec_superblock sb;
502
503 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
504 return -1;
505 }
506
rpcraigd1c226f2012-10-09 06:58:16 -0400507 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
508 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
509 SLOGE("ASEC finalize failed: couldn't construct mountPoint");
510 return -1;
511 }
Kenny Root344ca102012-04-03 17:23:01 -0700512
513 int result = 0;
514 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
515 result = Ext4::doMount(loopDevice, mountPoint, true, true, true);
516 } else {
517 result = Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false);
518 }
519
520 if (result) {
San Mehat97ac40e2010-03-24 10:24:19 -0700521 SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800522 return -1;
523 }
524
San Mehatd9a4e352010-03-12 13:32:47 -0800525 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700526 SLOGD("ASEC %s finalized", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800527 }
San Mehata19b2502010-01-06 10:33:53 -0800528 return 0;
529}
530
Kenny Root344ca102012-04-03 17:23:01 -0700531int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* filename) {
532 char asecFileName[255];
533 char loopDevice[255];
534 char mountPoint[255];
535
536 if (gid < AID_APP) {
537 SLOGE("Group ID is not in application range");
538 return -1;
539 }
540
541 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
542 SLOGE("Couldn't find ASEC %s", id);
543 return -1;
544 }
545
546 char idHash[33];
547 if (!asecHash(id, idHash, sizeof(idHash))) {
548 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
549 return -1;
550 }
551
552 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
553 SLOGE("Unable fix permissions during lookup on %s (%s)", id, strerror(errno));
554 return -1;
555 }
556
557 unsigned int nr_sec = 0;
558 struct asec_superblock sb;
559
560 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
561 return -1;
562 }
563
rpcraigd1c226f2012-10-09 06:58:16 -0400564 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
565 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
566 SLOGE("Unable remount to fix permissions for %s: couldn't construct mountpoint", id);
567 return -1;
568 }
Kenny Root344ca102012-04-03 17:23:01 -0700569
570 int result = 0;
571 if ((sb.c_opts & ASEC_SB_C_OPTS_EXT4) == 0) {
572 return 0;
573 }
574
575 int ret = Ext4::doMount(loopDevice, mountPoint,
576 false /* read-only */,
577 true /* remount */,
578 false /* executable */);
579 if (ret) {
580 SLOGE("Unable remount to fix permissions for %s (%s)", id, strerror(errno));
581 return -1;
582 }
583
584 char *paths[] = { mountPoint, NULL };
585
586 FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL);
587 if (fts) {
588 // Traverse the entire hierarchy and chown to system UID.
589 for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
590 // We don't care about the lost+found directory.
591 if (!strcmp(ftsent->fts_name, "lost+found")) {
592 continue;
593 }
594
595 /*
596 * There can only be one file marked as private right now.
597 * This should be more robust, but it satisfies the requirements
598 * we have for right now.
599 */
600 const bool privateFile = !strcmp(ftsent->fts_name, filename);
601
602 int fd = open(ftsent->fts_accpath, O_NOFOLLOW);
603 if (fd < 0) {
604 SLOGE("Couldn't open file %s: %s", ftsent->fts_accpath, strerror(errno));
605 result = -1;
606 continue;
607 }
608
609 result |= fchown(fd, AID_SYSTEM, privateFile? gid : AID_SYSTEM);
610
611 if (ftsent->fts_info & FTS_D) {
Kenny Root1a673c82012-05-10 16:45:29 -0700612 result |= fchmod(fd, 0755);
Kenny Root348c8ab2012-05-10 15:39:53 -0700613 } else if (ftsent->fts_info & FTS_F) {
Kenny Root344ca102012-04-03 17:23:01 -0700614 result |= fchmod(fd, privateFile ? 0640 : 0644);
615 }
616 close(fd);
617 }
618 fts_close(fts);
619
620 // Finally make the directory readable by everyone.
621 int dirfd = open(mountPoint, O_DIRECTORY);
622 if (dirfd < 0 || fchmod(dirfd, 0755)) {
623 SLOGE("Couldn't change owner of existing directory %s: %s", mountPoint, strerror(errno));
624 result |= -1;
625 }
626 close(dirfd);
627 } else {
628 result |= -1;
629 }
630
631 result |= Ext4::doMount(loopDevice, mountPoint,
632 true /* read-only */,
633 true /* remount */,
634 true /* execute */);
635
636 if (result) {
637 SLOGE("ASEC fix permissions failed (%s)", strerror(errno));
638 return -1;
639 }
640
641 if (mDebug) {
642 SLOGD("ASEC %s permissions fixed", id);
643 }
644 return 0;
645}
646
San Mehat048b0802010-01-23 08:17:06 -0800647int VolumeManager::renameAsec(const char *id1, const char *id2) {
Kenny Root344ca102012-04-03 17:23:01 -0700648 char asecFilename1[255];
San Mehat048b0802010-01-23 08:17:06 -0800649 char *asecFilename2;
650 char mountPoint[255];
651
Kenny Root344ca102012-04-03 17:23:01 -0700652 const char *dir;
653
654 if (findAsec(id1, asecFilename1, sizeof(asecFilename1), &dir)) {
655 SLOGE("Couldn't find ASEC %s", id1);
656 return -1;
657 }
658
659 asprintf(&asecFilename2, "%s/%s.asec", dir, id2);
San Mehat048b0802010-01-23 08:17:06 -0800660
rpcraigd1c226f2012-10-09 06:58:16 -0400661 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
662 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
663 SLOGE("Rename failed: couldn't construct mountpoint");
664 goto out_err;
665 }
666
San Mehat048b0802010-01-23 08:17:06 -0800667 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700668 SLOGW("Rename attempt when src mounted");
San Mehat048b0802010-01-23 08:17:06 -0800669 errno = EBUSY;
670 goto out_err;
671 }
672
rpcraigd1c226f2012-10-09 06:58:16 -0400673 written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2);
674 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
675 SLOGE("Rename failed: couldn't construct mountpoint2");
676 goto out_err;
677 }
678
San Mehat96956ed2010-02-24 08:42:51 -0800679 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700680 SLOGW("Rename attempt when dst mounted");
San Mehat96956ed2010-02-24 08:42:51 -0800681 errno = EBUSY;
682 goto out_err;
683 }
684
San Mehat048b0802010-01-23 08:17:06 -0800685 if (!access(asecFilename2, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700686 SLOGE("Rename attempt when dst exists");
San Mehat048b0802010-01-23 08:17:06 -0800687 errno = EADDRINUSE;
688 goto out_err;
689 }
690
691 if (rename(asecFilename1, asecFilename2)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700692 SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
San Mehat048b0802010-01-23 08:17:06 -0800693 goto out_err;
694 }
695
San Mehat048b0802010-01-23 08:17:06 -0800696 free(asecFilename2);
697 return 0;
698
699out_err:
San Mehat048b0802010-01-23 08:17:06 -0800700 free(asecFilename2);
701 return -1;
702}
703
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700704#define UNMOUNT_RETRIES 5
705#define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
San Mehat4ba89482010-02-18 09:00:18 -0800706int VolumeManager::unmountAsec(const char *id, bool force) {
San Mehata19b2502010-01-06 10:33:53 -0800707 char asecFileName[255];
708 char mountPoint[255];
709
Kenny Root344ca102012-04-03 17:23:01 -0700710 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
711 SLOGE("Couldn't find ASEC %s", id);
712 return -1;
713 }
714
rpcraigd1c226f2012-10-09 06:58:16 -0400715 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
716 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
717 SLOGE("ASEC unmount failed for %s: couldn't construct mountpoint", id);
718 return -1;
719 }
San Mehata19b2502010-01-06 10:33:53 -0800720
San Mehatd9a4e352010-03-12 13:32:47 -0800721 char idHash[33];
722 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700723 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800724 return -1;
725 }
726
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700727 return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
728}
729
Kenny Root508c0e12010-07-12 09:59:49 -0700730int VolumeManager::unmountObb(const char *fileName, bool force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700731 char mountPoint[255];
732
733 char idHash[33];
734 if (!asecHash(fileName, idHash, sizeof(idHash))) {
735 SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
736 return -1;
737 }
738
rpcraigd1c226f2012-10-09 06:58:16 -0400739 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
740 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
741 SLOGE("OBB unmount failed for %s: couldn't construct mountpoint", fileName);
742 return -1;
743 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700744
745 return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
746}
747
748int VolumeManager::unmountLoopImage(const char *id, const char *idHash,
749 const char *fileName, const char *mountPoint, bool force) {
San Mehat0586d542010-01-12 15:38:59 -0800750 if (!isMountpointMounted(mountPoint)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700751 SLOGE("Unmount request for %s when not mounted", id);
Kenny Root918e5f92010-09-30 18:00:52 -0700752 errno = ENOENT;
San Mehatb78a32c2010-01-10 13:02:12 -0800753 return -1;
754 }
San Mehat23969932010-01-09 07:08:06 -0800755
San Mehatb78a32c2010-01-10 13:02:12 -0800756 int i, rc;
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700757 for (i = 1; i <= UNMOUNT_RETRIES; i++) {
San Mehatb78a32c2010-01-10 13:02:12 -0800758 rc = umount(mountPoint);
759 if (!rc) {
760 break;
San Mehata19b2502010-01-06 10:33:53 -0800761 }
San Mehatb78a32c2010-01-10 13:02:12 -0800762 if (rc && (errno == EINVAL || errno == ENOENT)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700763 SLOGI("Container %s unmounted OK", id);
San Mehatb78a32c2010-01-10 13:02:12 -0800764 rc = 0;
765 break;
San Mehata19b2502010-01-06 10:33:53 -0800766 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700767 SLOGW("%s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -0800768 id, i, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800769
San Mehat4ba89482010-02-18 09:00:18 -0800770 int action = 0; // default is to just complain
771
772 if (force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700773 if (i > (UNMOUNT_RETRIES - 2))
San Mehat4ba89482010-02-18 09:00:18 -0800774 action = 2; // SIGKILL
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700775 else if (i > (UNMOUNT_RETRIES - 3))
San Mehat4ba89482010-02-18 09:00:18 -0800776 action = 1; // SIGHUP
777 }
San Mehat8c940ef2010-02-13 14:19:53 -0800778
San Mehat586536c2010-02-16 17:12:00 -0800779 Process::killProcessesWithOpenFiles(mountPoint, action);
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700780 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehatb78a32c2010-01-10 13:02:12 -0800781 }
782
783 if (rc) {
San Mehat4ba89482010-02-18 09:00:18 -0800784 errno = EBUSY;
San Mehat97ac40e2010-03-24 10:24:19 -0700785 SLOGE("Failed to unmount container %s (%s)", id, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800786 return -1;
787 }
788
San Mehat12f4b892010-02-24 11:43:22 -0800789 int retries = 10;
790
791 while(retries--) {
792 if (!rmdir(mountPoint)) {
793 break;
794 }
795
San Mehat97ac40e2010-03-24 10:24:19 -0700796 SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700797 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehat12f4b892010-02-24 11:43:22 -0800798 }
799
800 if (!retries) {
San Mehat97ac40e2010-03-24 10:24:19 -0700801 SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
San Mehatf5c61982010-02-03 11:04:46 -0800802 }
San Mehat88705162010-01-15 09:26:28 -0800803
San Mehatd9a4e352010-03-12 13:32:47 -0800804 if (Devmapper::destroy(idHash) && errno != ENXIO) {
San Mehat97ac40e2010-03-24 10:24:19 -0700805 SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800806 }
807
808 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800809 if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800810 Loop::destroyByDevice(loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800811 } else {
Kenny Rootfb7c4d52010-06-30 18:48:41 -0700812 SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800813 }
San Mehat88705162010-01-15 09:26:28 -0800814
815 AsecIdCollection::iterator it;
816 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
Kenny Rootcbacf782010-09-24 15:11:48 -0700817 ContainerData* cd = *it;
818 if (!strcmp(cd->id, id)) {
San Mehat88705162010-01-15 09:26:28 -0800819 free(*it);
820 mActiveContainers->erase(it);
821 break;
822 }
823 }
824 if (it == mActiveContainers->end()) {
San Mehat97ac40e2010-03-24 10:24:19 -0700825 SLOGW("mActiveContainers is inconsistent!");
San Mehat88705162010-01-15 09:26:28 -0800826 }
San Mehatb78a32c2010-01-10 13:02:12 -0800827 return 0;
828}
829
San Mehat4ba89482010-02-18 09:00:18 -0800830int VolumeManager::destroyAsec(const char *id, bool force) {
San Mehatb78a32c2010-01-10 13:02:12 -0800831 char asecFileName[255];
832 char mountPoint[255];
833
Kenny Root344ca102012-04-03 17:23:01 -0700834 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
835 SLOGE("Couldn't find ASEC %s", id);
836 return -1;
837 }
838
rpcraigd1c226f2012-10-09 06:58:16 -0400839 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
840 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
841 SLOGE("ASEC destroy failed for %s: couldn't construct mountpoint", id);
842 return -1;
843 }
San Mehatb78a32c2010-01-10 13:02:12 -0800844
San Mehat0586d542010-01-12 15:38:59 -0800845 if (isMountpointMounted(mountPoint)) {
San Mehatd9a4e352010-03-12 13:32:47 -0800846 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700847 SLOGD("Unmounting container before destroy");
San Mehatd9a4e352010-03-12 13:32:47 -0800848 }
San Mehat4ba89482010-02-18 09:00:18 -0800849 if (unmountAsec(id, force)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700850 SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800851 return -1;
852 }
853 }
San Mehata19b2502010-01-06 10:33:53 -0800854
San Mehat0586d542010-01-12 15:38:59 -0800855 if (unlink(asecFileName)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700856 SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800857 return -1;
858 }
San Mehata19b2502010-01-06 10:33:53 -0800859
San Mehatd9a4e352010-03-12 13:32:47 -0800860 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700861 SLOGD("ASEC %s destroyed", id);
San Mehatd9a4e352010-03-12 13:32:47 -0800862 }
San Mehata19b2502010-01-06 10:33:53 -0800863 return 0;
864}
865
Kenny Root344ca102012-04-03 17:23:01 -0700866bool VolumeManager::isAsecInDirectory(const char *dir, const char *asecName) const {
867 int dirfd = open(dir, O_DIRECTORY);
868 if (dirfd < 0) {
869 SLOGE("Couldn't open internal ASEC dir (%s)", strerror(errno));
870 return -1;
871 }
872
873 bool ret = false;
874
875 if (!faccessat(dirfd, asecName, F_OK, AT_SYMLINK_NOFOLLOW)) {
876 ret = true;
877 }
878
879 close(dirfd);
880
881 return ret;
882}
883
884int VolumeManager::findAsec(const char *id, char *asecPath, size_t asecPathLen,
885 const char **directory) const {
886 int dirfd, fd;
887 const int idLen = strlen(id);
888 char *asecName;
889
890 if (asprintf(&asecName, "%s.asec", id) < 0) {
891 SLOGE("Couldn't allocate string to write ASEC name");
892 return -1;
893 }
894
895 const char *dir;
896 if (isAsecInDirectory(Volume::SEC_ASECDIR_INT, asecName)) {
897 dir = Volume::SEC_ASECDIR_INT;
898 } else if (isAsecInDirectory(Volume::SEC_ASECDIR_EXT, asecName)) {
899 dir = Volume::SEC_ASECDIR_EXT;
900 } else {
901 free(asecName);
902 return -1;
903 }
904
905 if (directory != NULL) {
906 *directory = dir;
907 }
908
909 if (asecPath != NULL) {
910 int written = snprintf(asecPath, asecPathLen, "%s/%s", dir, asecName);
rpcraigd1c226f2012-10-09 06:58:16 -0400911 if ((written < 0) || (size_t(written) >= asecPathLen)) {
912 SLOGE("findAsec failed for %s: couldn't construct ASEC path", id);
Kenny Root344ca102012-04-03 17:23:01 -0700913 free(asecName);
914 return -1;
915 }
916 }
917
918 free(asecName);
919 return 0;
920}
921
San Mehata19b2502010-01-06 10:33:53 -0800922int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
923 char asecFileName[255];
924 char mountPoint[255];
925
Kenny Root344ca102012-04-03 17:23:01 -0700926 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
927 SLOGE("Couldn't find ASEC %s", id);
928 return -1;
929 }
930
rpcraigd1c226f2012-10-09 06:58:16 -0400931 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
932 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
933 SLOGE("ASEC mount failed: couldn't construct mountpoint", id);
934 return -1;
935 }
San Mehata19b2502010-01-06 10:33:53 -0800936
937 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700938 SLOGE("ASEC %s already mounted", id);
San Mehata19b2502010-01-06 10:33:53 -0800939 errno = EBUSY;
940 return -1;
941 }
942
San Mehatd9a4e352010-03-12 13:32:47 -0800943 char idHash[33];
944 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700945 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800946 return -1;
947 }
Kenny Root7b18a7b2010-03-15 13:13:41 -0700948
San Mehata19b2502010-01-06 10:33:53 -0800949 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800950 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
951 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700952 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800953 return -1;
954 }
San Mehatd9a4e352010-03-12 13:32:47 -0800955 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700956 SLOGD("New loop device created at %s", loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800957 }
San Mehatb78a32c2010-01-10 13:02:12 -0800958 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800959 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700960 SLOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800961 }
San Mehatb78a32c2010-01-10 13:02:12 -0800962 }
963
964 char dmDevice[255];
965 bool cleanupDm = false;
San Mehatfcf24fe2010-03-03 12:37:32 -0800966 int fd;
967 unsigned int nr_sec = 0;
San Mehatfcf24fe2010-03-03 12:37:32 -0800968 struct asec_superblock sb;
San Mehatfcf24fe2010-03-03 12:37:32 -0800969
Kenny Root344ca102012-04-03 17:23:01 -0700970 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
971 return -1;
972 }
San Mehatfcf24fe2010-03-03 12:37:32 -0800973
San Mehatd9a4e352010-03-12 13:32:47 -0800974 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700975 SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatd9a4e352010-03-12 13:32:47 -0800976 }
San Mehatfcf24fe2010-03-03 12:37:32 -0800977 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
San Mehat97ac40e2010-03-24 10:24:19 -0700978 SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatfcf24fe2010-03-03 12:37:32 -0800979 Loop::destroyByDevice(loopDevice);
980 errno = EMEDIUMTYPE;
981 return -1;
982 }
983 nr_sec--; // We don't want the devmapping to extend onto our superblock
984
San Mehatb78a32c2010-01-10 13:02:12 -0800985 if (strcmp(key, "none")) {
San Mehatd9a4e352010-03-12 13:32:47 -0800986 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
987 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
San Mehatb78a32c2010-01-10 13:02:12 -0800988 dmDevice, sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700989 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800990 Loop::destroyByDevice(loopDevice);
991 return -1;
992 }
San Mehatd9a4e352010-03-12 13:32:47 -0800993 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700994 SLOGD("New devmapper instance created at %s", dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800995 }
San Mehatb78a32c2010-01-10 13:02:12 -0800996 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800997 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -0700998 SLOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800999 }
San Mehatb78a32c2010-01-10 13:02:12 -08001000 }
1001 cleanupDm = true;
1002 } else {
1003 strcpy(dmDevice, loopDevice);
San Mehata19b2502010-01-06 10:33:53 -08001004 }
1005
Kenny Root344ca102012-04-03 17:23:01 -07001006 if (mkdir(mountPoint, 0000)) {
San Mehatb78a32c2010-01-10 13:02:12 -08001007 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -07001008 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001009 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -08001010 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -08001011 }
1012 Loop::destroyByDevice(loopDevice);
1013 return -1;
1014 }
San Mehata19b2502010-01-06 10:33:53 -08001015 }
1016
Kenny Rootcdc2a1c2012-05-03 13:49:46 -07001017 /*
1018 * The device mapper node needs to be created. Sometimes it takes a
1019 * while. Wait for up to 1 second. We could also inspect incoming uevents,
1020 * but that would take more effort.
1021 */
1022 int tries = 25;
1023 while (tries--) {
1024 if (!access(dmDevice, F_OK) || errno != ENOENT) {
1025 break;
1026 }
1027 usleep(40 * 1000);
1028 }
1029
Kenny Root344ca102012-04-03 17:23:01 -07001030 int result;
1031 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
1032 result = Ext4::doMount(dmDevice, mountPoint, true, false, true);
1033 } else {
1034 result = Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0, 0222, false);
1035 }
1036
1037 if (result) {
San Mehat97ac40e2010-03-24 10:24:19 -07001038 SLOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001039 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -08001040 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -08001041 }
1042 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -08001043 return -1;
1044 }
1045
Kenny Rootcbacf782010-09-24 15:11:48 -07001046 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehatd9a4e352010-03-12 13:32:47 -08001047 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001048 SLOGD("ASEC %s mounted", id);
San Mehatd9a4e352010-03-12 13:32:47 -08001049 }
San Mehata19b2502010-01-06 10:33:53 -08001050 return 0;
1051}
1052
Kenny Root93ecb382012-08-09 11:28:37 -07001053Volume* VolumeManager::getVolumeForFile(const char *fileName) {
1054 VolumeCollection::iterator i;
1055
1056 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
Jeff Sharkeyba6ae8d2013-07-15 18:14:25 -07001057 const char* mountPoint = (*i)->getFuseMountpoint();
Kenny Root93ecb382012-08-09 11:28:37 -07001058 if (!strncmp(fileName, mountPoint, strlen(mountPoint))) {
1059 return *i;
1060 }
1061 }
1062
1063 return NULL;
1064}
1065
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001066/**
1067 * Mounts an image file <code>img</code>.
1068 */
Jeff Sharkey69479042012-09-25 16:14:57 -07001069int VolumeManager::mountObb(const char *img, const char *key, int ownerGid) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001070 char mountPoint[255];
1071
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001072 char idHash[33];
1073 if (!asecHash(img, idHash, sizeof(idHash))) {
1074 SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
1075 return -1;
1076 }
1077
rpcraigd1c226f2012-10-09 06:58:16 -04001078 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
1079 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1080 SLOGE("OBB mount failed: couldn't construct mountpoint", img);
1081 return -1;
1082 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001083
1084 if (isMountpointMounted(mountPoint)) {
1085 SLOGE("Image %s already mounted", img);
1086 errno = EBUSY;
1087 return -1;
1088 }
1089
1090 char loopDevice[255];
1091 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
1092 if (Loop::create(idHash, img, loopDevice, sizeof(loopDevice))) {
1093 SLOGE("Image loop device creation failed (%s)", strerror(errno));
1094 return -1;
1095 }
1096 if (mDebug) {
1097 SLOGD("New loop device created at %s", loopDevice);
1098 }
1099 } else {
1100 if (mDebug) {
1101 SLOGD("Found active loopback for %s at %s", img, loopDevice);
1102 }
1103 }
1104
1105 char dmDevice[255];
1106 bool cleanupDm = false;
1107 int fd;
1108 unsigned int nr_sec = 0;
1109
1110 if ((fd = open(loopDevice, O_RDWR)) < 0) {
1111 SLOGE("Failed to open loopdevice (%s)", strerror(errno));
1112 Loop::destroyByDevice(loopDevice);
1113 return -1;
1114 }
1115
1116 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
1117 SLOGE("Failed to get loop size (%s)", strerror(errno));
1118 Loop::destroyByDevice(loopDevice);
1119 close(fd);
1120 return -1;
1121 }
1122
1123 close(fd);
1124
1125 if (strcmp(key, "none")) {
1126 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
1127 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
1128 dmDevice, sizeof(dmDevice))) {
1129 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
1130 Loop::destroyByDevice(loopDevice);
1131 return -1;
1132 }
1133 if (mDebug) {
1134 SLOGD("New devmapper instance created at %s", dmDevice);
1135 }
1136 } else {
1137 if (mDebug) {
1138 SLOGD("Found active devmapper for %s at %s", img, dmDevice);
1139 }
1140 }
1141 cleanupDm = true;
1142 } else {
1143 strcpy(dmDevice, loopDevice);
1144 }
1145
1146 if (mkdir(mountPoint, 0755)) {
1147 if (errno != EEXIST) {
1148 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
1149 if (cleanupDm) {
1150 Devmapper::destroy(idHash);
1151 }
1152 Loop::destroyByDevice(loopDevice);
1153 return -1;
1154 }
1155 }
1156
Jeff Sharkey69479042012-09-25 16:14:57 -07001157 if (Fat::doMount(dmDevice, mountPoint, true, false, true, 0, ownerGid,
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001158 0227, false)) {
1159 SLOGE("Image mount failed (%s)", strerror(errno));
1160 if (cleanupDm) {
1161 Devmapper::destroy(idHash);
1162 }
1163 Loop::destroyByDevice(loopDevice);
1164 return -1;
1165 }
1166
Kenny Rootcbacf782010-09-24 15:11:48 -07001167 mActiveContainers->push_back(new ContainerData(strdup(img), OBB));
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001168 if (mDebug) {
1169 SLOGD("Image %s mounted", img);
1170 }
1171 return 0;
1172}
1173
San Mehat49e2bce2009-10-12 16:29:01 -07001174int VolumeManager::mountVolume(const char *label) {
1175 Volume *v = lookupVolume(label);
1176
1177 if (!v) {
1178 errno = ENOENT;
1179 return -1;
1180 }
1181
San Mehata2677e42009-12-13 10:40:18 -08001182 return v->mountVol();
1183}
1184
Kenny Root508c0e12010-07-12 09:59:49 -07001185int VolumeManager::listMountedObbs(SocketClient* cli) {
1186 char device[256];
1187 char mount_path[256];
1188 char rest[256];
1189 FILE *fp;
1190 char line[1024];
1191
1192 if (!(fp = fopen("/proc/mounts", "r"))) {
1193 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
1194 return -1;
1195 }
1196
1197 // Create a string to compare against that has a trailing slash
Kenny Root93ecb382012-08-09 11:28:37 -07001198 int loopDirLen = strlen(Volume::LOOPDIR);
Kenny Root508c0e12010-07-12 09:59:49 -07001199 char loopDir[loopDirLen + 2];
1200 strcpy(loopDir, Volume::LOOPDIR);
1201 loopDir[loopDirLen++] = '/';
1202 loopDir[loopDirLen] = '\0';
1203
1204 while(fgets(line, sizeof(line), fp)) {
1205 line[strlen(line)-1] = '\0';
1206
1207 /*
1208 * Should look like:
1209 * /dev/block/loop0 /mnt/obb/fc99df1323fd36424f864dcb76b76d65 ...
1210 */
1211 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1212
1213 if (!strncmp(mount_path, loopDir, loopDirLen)) {
1214 int fd = open(device, O_RDONLY);
1215 if (fd >= 0) {
1216 struct loop_info64 li;
1217 if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
1218 cli->sendMsg(ResponseCode::AsecListResult,
1219 (const char*) li.lo_file_name, false);
1220 }
1221 close(fd);
1222 }
1223 }
1224 }
1225
1226 fclose(fp);
1227 return 0;
1228}
1229
San Mehateba65e92010-01-29 05:15:16 -08001230int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
1231 Volume *v = lookupVolume(label);
1232
1233 if (!v) {
1234 errno = ENOENT;
1235 return -1;
1236 }
1237
1238 if (strcmp(method, "ums")) {
1239 errno = ENOSYS;
1240 return -1;
1241 }
1242
1243 if (v->getState() != Volume::State_Shared) {
San Mehateba65e92010-01-29 05:15:16 -08001244 *enabled = false;
San Mehatb9aed742010-02-04 15:07:01 -08001245 } else {
1246 *enabled = true;
San Mehateba65e92010-01-29 05:15:16 -08001247 }
1248 return 0;
1249}
1250
San Mehata2677e42009-12-13 10:40:18 -08001251int VolumeManager::shareVolume(const char *label, const char *method) {
1252 Volume *v = lookupVolume(label);
1253
1254 if (!v) {
1255 errno = ENOENT;
1256 return -1;
1257 }
1258
1259 /*
1260 * Eventually, we'll want to support additional share back-ends,
1261 * some of which may work while the media is mounted. For now,
1262 * we just support UMS
1263 */
1264 if (strcmp(method, "ums")) {
1265 errno = ENOSYS;
1266 return -1;
1267 }
1268
1269 if (v->getState() == Volume::State_NoMedia) {
1270 errno = ENODEV;
1271 return -1;
1272 }
1273
San Mehat49e2bce2009-10-12 16:29:01 -07001274 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -08001275 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -07001276 errno = EBUSY;
1277 return -1;
1278 }
1279
Ken Sumrall3b170052011-07-11 15:38:57 -07001280 if (mVolManagerDisabled) {
1281 errno = EBUSY;
1282 return -1;
1283 }
1284
Mike Lockwood2dfe2972010-09-17 18:50:51 -04001285 dev_t d = v->getShareDevice();
San Mehata2677e42009-12-13 10:40:18 -08001286 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
1287 // This volume does not support raw disk access
1288 errno = EINVAL;
1289 return -1;
1290 }
1291
1292 int fd;
1293 char nodepath[255];
rpcraigd1c226f2012-10-09 06:58:16 -04001294 int written = snprintf(nodepath,
San Mehata2677e42009-12-13 10:40:18 -08001295 sizeof(nodepath), "/dev/block/vold/%d:%d",
1296 MAJOR(d), MINOR(d));
1297
rpcraigd1c226f2012-10-09 06:58:16 -04001298 if ((written < 0) || (size_t(written) >= sizeof(nodepath))) {
1299 SLOGE("shareVolume failed: couldn't construct nodepath");
1300 return -1;
1301 }
1302
Mike Lockwood97f2fc12011-06-07 10:51:38 -07001303 if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001304 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001305 return -1;
1306 }
1307
1308 if (write(fd, nodepath, strlen(nodepath)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001309 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001310 close(fd);
1311 return -1;
1312 }
1313
1314 close(fd);
1315 v->handleVolumeShared();
Mike Lockwooda28056b2010-10-28 15:21:24 -04001316 if (mUmsSharingCount++ == 0) {
1317 FILE* fp;
1318 mSavedDirtyRatio = -1; // in case we fail
1319 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1320 char line[16];
1321 if (fgets(line, sizeof(line), fp) && sscanf(line, "%d", &mSavedDirtyRatio)) {
1322 fprintf(fp, "%d\n", mUmsDirtyRatio);
1323 } else {
1324 SLOGE("Failed to read dirty_ratio (%s)", strerror(errno));
1325 }
1326 fclose(fp);
1327 } else {
1328 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1329 }
1330 }
San Mehata2677e42009-12-13 10:40:18 -08001331 return 0;
1332}
1333
1334int VolumeManager::unshareVolume(const char *label, const char *method) {
1335 Volume *v = lookupVolume(label);
1336
1337 if (!v) {
1338 errno = ENOENT;
1339 return -1;
1340 }
1341
1342 if (strcmp(method, "ums")) {
1343 errno = ENOSYS;
1344 return -1;
1345 }
1346
1347 if (v->getState() != Volume::State_Shared) {
1348 errno = EINVAL;
1349 return -1;
1350 }
1351
San Mehata2677e42009-12-13 10:40:18 -08001352 int fd;
Mike Lockwood97f2fc12011-06-07 10:51:38 -07001353 if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001354 SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001355 return -1;
1356 }
1357
1358 char ch = 0;
1359 if (write(fd, &ch, 1) < 0) {
San Mehat97ac40e2010-03-24 10:24:19 -07001360 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
San Mehata2677e42009-12-13 10:40:18 -08001361 close(fd);
1362 return -1;
1363 }
1364
1365 close(fd);
1366 v->handleVolumeUnshared();
Mike Lockwooda28056b2010-10-28 15:21:24 -04001367 if (--mUmsSharingCount == 0 && mSavedDirtyRatio != -1) {
1368 FILE* fp;
1369 if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1370 fprintf(fp, "%d\n", mSavedDirtyRatio);
1371 fclose(fp);
1372 } else {
1373 SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1374 }
1375 mSavedDirtyRatio = -1;
1376 }
San Mehata2677e42009-12-13 10:40:18 -08001377 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -07001378}
1379
Ken Sumrall3b170052011-07-11 15:38:57 -07001380extern "C" int vold_disableVol(const char *label) {
Ken Sumrall29d8da82011-05-18 17:20:07 -07001381 VolumeManager *vm = VolumeManager::Instance();
Ken Sumrall3b170052011-07-11 15:38:57 -07001382 vm->disableVolumeManager();
1383 vm->unshareVolume(label, "ums");
Ken Sumrall0b8b5972011-08-31 16:14:23 -07001384 return vm->unmountVolume(label, true, false);
Ken Sumrall29d8da82011-05-18 17:20:07 -07001385}
1386
1387extern "C" int vold_getNumDirectVolumes(void) {
1388 VolumeManager *vm = VolumeManager::Instance();
1389 return vm->getNumDirectVolumes();
1390}
1391
1392int VolumeManager::getNumDirectVolumes(void) {
1393 VolumeCollection::iterator i;
1394 int n=0;
1395
1396 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1397 if ((*i)->getShareDevice() != (dev_t)0) {
1398 n++;
1399 }
1400 }
1401 return n;
1402}
1403
1404extern "C" int vold_getDirectVolumeList(struct volume_info *vol_list) {
1405 VolumeManager *vm = VolumeManager::Instance();
1406 return vm->getDirectVolumeList(vol_list);
1407}
1408
1409int VolumeManager::getDirectVolumeList(struct volume_info *vol_list) {
1410 VolumeCollection::iterator i;
1411 int n=0;
1412 dev_t d;
1413
1414 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1415 if ((d=(*i)->getShareDevice()) != (dev_t)0) {
1416 (*i)->getVolInfo(&vol_list[n]);
1417 snprintf(vol_list[n].blk_dev, sizeof(vol_list[n].blk_dev),
1418 "/dev/block/vold/%d:%d",MAJOR(d), MINOR(d));
1419 n++;
1420 }
1421 }
1422
1423 return 0;
1424}
1425
Ken Sumrall0b8b5972011-08-31 16:14:23 -07001426int VolumeManager::unmountVolume(const char *label, bool force, bool revert) {
San Mehat49e2bce2009-10-12 16:29:01 -07001427 Volume *v = lookupVolume(label);
1428
1429 if (!v) {
1430 errno = ENOENT;
1431 return -1;
1432 }
1433
San Mehata2677e42009-12-13 10:40:18 -08001434 if (v->getState() == Volume::State_NoMedia) {
1435 errno = ENODEV;
1436 return -1;
1437 }
1438
San Mehat49e2bce2009-10-12 16:29:01 -07001439 if (v->getState() != Volume::State_Mounted) {
San Mehat97ac40e2010-03-24 10:24:19 -07001440 SLOGW("Attempt to unmount volume which isn't mounted (%d)\n",
San Mehata2677e42009-12-13 10:40:18 -08001441 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -07001442 errno = EBUSY;
Ken Sumrall319b1042011-06-14 14:01:55 -07001443 return UNMOUNT_NOT_MOUNTED_ERR;
San Mehat49e2bce2009-10-12 16:29:01 -07001444 }
1445
San Mehat1a06eda2010-04-15 12:58:50 -07001446 cleanupAsec(v, force);
San Mehat88705162010-01-15 09:26:28 -08001447
Ken Sumrall0b8b5972011-08-31 16:14:23 -07001448 return v->unmountVol(force, revert);
San Mehat49e2bce2009-10-12 16:29:01 -07001449}
1450
Ken Sumrall425524d2012-06-14 20:55:28 -07001451extern "C" int vold_unmountAllAsecs(void) {
1452 int rc;
1453
1454 VolumeManager *vm = VolumeManager::Instance();
1455 rc = vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_EXT);
1456 if (vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_INT)) {
1457 rc = -1;
1458 }
1459 return rc;
1460}
1461
1462#define ID_BUF_LEN 256
1463#define ASEC_SUFFIX ".asec"
1464#define ASEC_SUFFIX_LEN (sizeof(ASEC_SUFFIX) - 1)
1465int VolumeManager::unmountAllAsecsInDir(const char *directory) {
1466 DIR *d = opendir(directory);
1467 int rc = 0;
1468
1469 if (!d) {
1470 SLOGE("Could not open asec dir %s", directory);
1471 return -1;
1472 }
1473
1474 size_t dirent_len = offsetof(struct dirent, d_name) +
Elliott Hughes8c480f72012-10-26 16:57:19 -07001475 fpathconf(dirfd(d), _PC_NAME_MAX) + 1;
Ken Sumrall425524d2012-06-14 20:55:28 -07001476
1477 struct dirent *dent = (struct dirent *) malloc(dirent_len);
1478 if (dent == NULL) {
1479 SLOGE("Failed to allocate memory for asec dir");
1480 return -1;
1481 }
1482
1483 struct dirent *result;
1484 while (!readdir_r(d, dent, &result) && result != NULL) {
1485 if (dent->d_name[0] == '.')
1486 continue;
1487 if (dent->d_type != DT_REG)
1488 continue;
1489 size_t name_len = strlen(dent->d_name);
1490 if (name_len > 5 && name_len < (ID_BUF_LEN + ASEC_SUFFIX_LEN - 1) &&
1491 !strcmp(&dent->d_name[name_len - 5], ASEC_SUFFIX)) {
1492 char id[ID_BUF_LEN];
1493 strlcpy(id, dent->d_name, name_len - 4);
1494 if (unmountAsec(id, true)) {
1495 /* Register the error, but try to unmount more asecs */
1496 rc = -1;
1497 }
1498 }
1499 }
1500 closedir(d);
1501
1502 free(dent);
1503
1504 return rc;
1505}
1506
San Mehata2677e42009-12-13 10:40:18 -08001507/*
1508 * Looks up a volume by it's label or mount-point
1509 */
San Mehat49e2bce2009-10-12 16:29:01 -07001510Volume *VolumeManager::lookupVolume(const char *label) {
1511 VolumeCollection::iterator i;
1512
1513 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -08001514 if (label[0] == '/') {
Jeff Sharkeyba6ae8d2013-07-15 18:14:25 -07001515 if (!strcmp(label, (*i)->getFuseMountpoint()))
San Mehata2677e42009-12-13 10:40:18 -08001516 return (*i);
1517 } else {
1518 if (!strcmp(label, (*i)->getLabel()))
1519 return (*i);
1520 }
San Mehat49e2bce2009-10-12 16:29:01 -07001521 }
1522 return NULL;
1523}
San Mehata19b2502010-01-06 10:33:53 -08001524
1525bool VolumeManager::isMountpointMounted(const char *mp)
1526{
1527 char device[256];
1528 char mount_path[256];
1529 char rest[256];
1530 FILE *fp;
1531 char line[1024];
1532
1533 if (!(fp = fopen("/proc/mounts", "r"))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001534 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001535 return false;
1536 }
1537
1538 while(fgets(line, sizeof(line), fp)) {
1539 line[strlen(line)-1] = '\0';
1540 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1541 if (!strcmp(mount_path, mp)) {
1542 fclose(fp);
1543 return true;
1544 }
San Mehata19b2502010-01-06 10:33:53 -08001545 }
1546
1547 fclose(fp);
1548 return false;
1549}
1550
San Mehat1a06eda2010-04-15 12:58:50 -07001551int VolumeManager::cleanupAsec(Volume *v, bool force) {
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001552 int rc = 0;
Kenny Root93ecb382012-08-09 11:28:37 -07001553
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001554 char asecFileName[255];
1555
1556 AsecIdCollection removeAsec;
1557 AsecIdCollection removeObb;
1558
Kenny Root93ecb382012-08-09 11:28:37 -07001559 for (AsecIdCollection::iterator it = mActiveContainers->begin(); it != mActiveContainers->end();
1560 ++it) {
Kenny Rootcbacf782010-09-24 15:11:48 -07001561 ContainerData* cd = *it;
Kenny Root93ecb382012-08-09 11:28:37 -07001562
Kenny Rootcbacf782010-09-24 15:11:48 -07001563 if (cd->type == ASEC) {
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001564 if (findAsec(cd->id, asecFileName, sizeof(asecFileName))) {
1565 SLOGE("Couldn't find ASEC %s; cleaning up", cd->id);
1566 removeAsec.push_back(cd);
1567 } else {
1568 SLOGD("Found ASEC at path %s", asecFileName);
1569 if (!strncmp(asecFileName, Volume::SEC_ASECDIR_EXT,
1570 strlen(Volume::SEC_ASECDIR_EXT))) {
1571 removeAsec.push_back(cd);
1572 }
1573 }
Kenny Rootcbacf782010-09-24 15:11:48 -07001574 } else if (cd->type == OBB) {
Kenny Root93ecb382012-08-09 11:28:37 -07001575 if (v == getVolumeForFile(cd->id)) {
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001576 removeObb.push_back(cd);
Kenny Rootcbacf782010-09-24 15:11:48 -07001577 }
1578 } else {
1579 SLOGE("Unknown container type %d!", cd->type);
San Mehat1a06eda2010-04-15 12:58:50 -07001580 }
1581 }
Kenny Root93ecb382012-08-09 11:28:37 -07001582
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001583 for (AsecIdCollection::iterator it = removeAsec.begin(); it != removeAsec.end(); ++it) {
Kenny Root93ecb382012-08-09 11:28:37 -07001584 ContainerData *cd = *it;
Jeff Sharkey8c2c15b2013-10-17 15:17:19 -07001585 SLOGI("Unmounting ASEC %s (dependent on %s)", cd->id, v->getLabel());
1586 if (unmountAsec(cd->id, force)) {
1587 SLOGE("Failed to unmount ASEC %s (%s)", cd->id, strerror(errno));
1588 rc = -1;
1589 }
1590 }
1591
1592 for (AsecIdCollection::iterator it = removeObb.begin(); it != removeObb.end(); ++it) {
1593 ContainerData *cd = *it;
1594 SLOGI("Unmounting OBB %s (dependent on %s)", cd->id, v->getLabel());
Kenny Root93ecb382012-08-09 11:28:37 -07001595 if (unmountObb(cd->id, force)) {
1596 SLOGE("Failed to unmount OBB %s (%s)", cd->id, strerror(errno));
1597 rc = -1;
1598 }
1599 }
1600
1601 return rc;
San Mehat1a06eda2010-04-15 12:58:50 -07001602}
1603
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001604int VolumeManager::mkdirs(char* path) {
1605 // Require that path lives under a volume we manage
1606 const char* emulated_source = getenv("EMULATED_STORAGE_SOURCE");
1607 const char* root = NULL;
Marco Nelissen5ab02e72013-10-15 15:22:28 -07001608 if (emulated_source && !strncmp(path, emulated_source, strlen(emulated_source))) {
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001609 root = emulated_source;
1610 } else {
1611 Volume* vol = getVolumeForFile(path);
1612 if (vol) {
1613 root = vol->getMountpoint();
1614 }
1615 }
1616
1617 if (!root) {
1618 SLOGE("Failed to find volume for %s", path);
1619 return -EINVAL;
1620 }
1621
1622 /* fs_mkdirs() does symlink checking and relative path enforcement */
1623 return fs_mkdirs(path, 0700);
1624}