1 /* 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> 18 #include <stdlib.h> 19 #include <string.h> 20 #include <errno.h> 21 #include <fcntl.h> 22 #include <fts.h> 23 #include <unistd.h> 24 #include <sys/stat.h> 25 #include <sys/types.h> 26 #include <sys/mount.h> 27 #include <dirent.h> 28 29 #include <linux/kdev_t.h> 30 31 #define LOG_TAG "Vold" 32 33 #include <openssl/md5.h> 34 35 #include <cutils/fs.h> 36 #include <cutils/log.h> 37 38 #include <sysutils/NetlinkEvent.h> 39 40 #include <private/android_filesystem_config.h> 41 42 #include "VolumeManager.h" 43 #include "DirectVolume.h" 44 #include "ResponseCode.h" 45 #include "Loop.h" 46 #include "Ext4.h" 47 #include "Fat.h" 48 #include "Devmapper.h" 49 #include "Process.h" 50 #include "Asec.h" 51 #include "cryptfs.h" 52 53 #define MASS_STORAGE_FILE_PATH "/sys/class/android_usb/android0/f_mass_storage/lun/file" 54 55 VolumeManager *VolumeManager::sInstance = NULL; 56 57 VolumeManager *VolumeManager::Instance() { 58 if (!sInstance) 59 sInstance = new VolumeManager(); 60 return sInstance; 61 } 62 63 VolumeManager::VolumeManager() { 64 mDebug = false; 65 mVolumes = new VolumeCollection(); 66 mActiveContainers = new AsecIdCollection(); 67 mBroadcaster = NULL; 68 mUmsSharingCount = 0; 69 mSavedDirtyRatio = -1; 70 // set dirty ratio to 0 when UMS is active 71 mUmsDirtyRatio = 0; 72 mVolManagerDisabled = 0; 73 } 74 75 VolumeManager::~VolumeManager() { 76 delete mVolumes; 77 delete mActiveContainers; 78 } 79 80 char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) { 81 static const char* digits = "0123456789abcdef"; 82 83 unsigned char sig[MD5_DIGEST_LENGTH]; 84 85 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); 96 errno = ESPIPE; 97 return NULL; 98 } 99 100 MD5(reinterpret_cast<const unsigned char*>(id), strlen(id), sig); 101 102 char *p = buffer; 103 for (int i = 0; i < MD5_DIGEST_LENGTH; i++) { 104 *p++ = digits[sig[i] >> 4]; 105 *p++ = digits[sig[i] & 0x0F]; 106 } 107 *p = '\0'; 108 109 return buffer; 110 } 111 112 void 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 120 int VolumeManager::start() { 121 return 0; 122 } 123 124 int VolumeManager::stop() { 125 return 0; 126 } 127 128 int VolumeManager::addVolume(Volume *v) { 129 mVolumes->push_back(v); 130 return 0; 131 } 132 133 void VolumeManager::handleBlockEvent(NetlinkEvent *evt) { 134 const char *devpath = evt->findParam("DEVPATH"); 135 136 /* Lookup a volume to handle this device */ 137 VolumeCollection::iterator it; 138 bool hit = false; 139 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) { 140 if (!(*it)->handleBlockEvent(evt)) { 141 #ifdef NETLINK_DEBUG 142 SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel()); 143 #endif 144 hit = true; 145 break; 146 } 147 } 148 149 if (!hit) { 150 #ifdef NETLINK_DEBUG 151 SLOGW("No volumes handled block event for '%s'", devpath); 152 #endif 153 } 154 } 155 156 int 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", 162 (*i)->getLabel(), (*i)->getFuseMountpoint(), 163 (*i)->getState()); 164 cli->sendMsg(ResponseCode::VolumeListResult, buffer, false); 165 free(buffer); 166 } 167 cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false); 168 return 0; 169 } 170 171 int VolumeManager::formatVolume(const char *label, bool wipe) { 172 Volume *v = lookupVolume(label); 173 174 if (!v) { 175 errno = ENOENT; 176 return -1; 177 } 178 179 if (mVolManagerDisabled) { 180 errno = EBUSY; 181 return -1; 182 } 183 184 return v->formatVol(wipe); 185 } 186 187 int 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); 195 int written = snprintf(mountPath, mountPathLen, "%s/%s", Volume::LOOPDIR, idHash); 196 if ((written < 0) || (written >= mountPathLen)) { 197 errno = EINVAL; 198 return -1; 199 } 200 201 if (access(mountPath, F_OK)) { 202 errno = ENOENT; 203 return -1; 204 } 205 206 return 0; 207 } 208 209 int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) { 210 char asecFileName[255]; 211 212 if (findAsec(id, asecFileName, sizeof(asecFileName))) { 213 SLOGE("Couldn't find ASEC %s", id); 214 return -1; 215 } 216 217 memset(buffer, 0, maxlen); 218 if (access(asecFileName, F_OK)) { 219 errno = ENOENT; 220 return -1; 221 } 222 223 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 230 return 0; 231 } 232 233 int VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxlen) { 234 char asecFileName[255]; 235 236 if (findAsec(id, asecFileName, sizeof(asecFileName))) { 237 SLOGE("Couldn't find ASEC %s", id); 238 return -1; 239 } 240 241 memset(buffer, 0, maxlen); 242 if (access(asecFileName, F_OK)) { 243 errno = ENOENT; 244 return -1; 245 } 246 247 int written = snprintf(buffer, maxlen, "%s", asecFileName); 248 if ((written < 0) || (written >= maxlen)) { 249 errno = EINVAL; 250 return -1; 251 } 252 253 return 0; 254 } 255 256 int VolumeManager::createAsec(const char *id, unsigned int numSectors, const char *fstype, 257 const char *key, const int ownerUid, bool isExternal) { 258 struct asec_superblock sb; 259 memset(&sb, 0, sizeof(sb)); 260 261 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 274 sb.magic = ASEC_SB_MAGIC; 275 sb.ver = ASEC_SB_VER; 276 277 if (numSectors < ((1024*1024)/512)) { 278 SLOGE("Invalid container size specified (%d sectors)", numSectors); 279 errno = EINVAL; 280 return -1; 281 } 282 283 if (lookupVolume(id)) { 284 SLOGE("ASEC id '%s' currently exists", id); 285 errno = EADDRINUSE; 286 return -1; 287 } 288 289 char asecFileName[255]; 290 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 300 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 } 305 306 if (!access(asecFileName, F_OK)) { 307 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)", 308 asecFileName, strerror(errno)); 309 errno = EADDRINUSE; 310 return -1; 311 } 312 313 /* 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)) { 325 SLOGE("ASEC image file creation failed (%s)", strerror(errno)); 326 return -1; 327 } 328 329 char idHash[33]; 330 if (!asecHash(id, idHash, sizeof(idHash))) { 331 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); 332 unlink(asecFileName); 333 return -1; 334 } 335 336 char loopDevice[255]; 337 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) { 338 SLOGE("ASEC loop device creation failed (%s)", strerror(errno)); 339 unlink(asecFileName); 340 return -1; 341 } 342 343 char dmDevice[255]; 344 bool cleanupDm = false; 345 346 if (strcmp(key, "none")) { 347 // XXX: This is all we support for now 348 sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH; 349 if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice, 350 sizeof(dmDevice))) { 351 SLOGE("ASEC device mapping failed (%s)", strerror(errno)); 352 Loop::destroyByDevice(loopDevice); 353 unlink(asecFileName); 354 return -1; 355 } 356 cleanupDm = true; 357 } else { 358 sb.c_cipher = ASEC_SB_C_CIPHER_NONE; 359 strcpy(dmDevice, loopDevice); 360 } 361 362 /* 363 * Drop down the superblock at the end of the file 364 */ 365 366 int sbfd = open(loopDevice, O_RDWR); 367 if (sbfd < 0) { 368 SLOGE("Failed to open new DM device for superblock write (%s)", strerror(errno)); 369 if (cleanupDm) { 370 Devmapper::destroy(idHash); 371 } 372 Loop::destroyByDevice(loopDevice); 373 unlink(asecFileName); 374 return -1; 375 } 376 377 if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) { 378 close(sbfd); 379 SLOGE("Failed to lseek for superblock (%s)", strerror(errno)); 380 if (cleanupDm) { 381 Devmapper::destroy(idHash); 382 } 383 Loop::destroyByDevice(loopDevice); 384 unlink(asecFileName); 385 return -1; 386 } 387 388 if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) { 389 close(sbfd); 390 SLOGE("Failed to write superblock (%s)", strerror(errno)); 391 if (cleanupDm) { 392 Devmapper::destroy(idHash); 393 } 394 Loop::destroyByDevice(loopDevice); 395 unlink(asecFileName); 396 return -1; 397 } 398 close(sbfd); 399 400 if (wantFilesystem) { 401 int formatStatus; 402 char mountPoint[255]; 403 404 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 } 414 415 if (usingExt4) { 416 formatStatus = Ext4::format(dmDevice, mountPoint); 417 } else { 418 formatStatus = Fat::format(dmDevice, numImgSectors, 0); 419 } 420 421 if (formatStatus < 0) { 422 SLOGE("ASEC fs format failed (%s)", strerror(errno)); 423 if (cleanupDm) { 424 Devmapper::destroy(idHash); 425 } 426 Loop::destroyByDevice(loopDevice); 427 unlink(asecFileName); 428 return -1; 429 } 430 431 if (mkdir(mountPoint, 0000)) { 432 if (errno != EEXIST) { 433 SLOGE("Mountpoint creation failed (%s)", strerror(errno)); 434 if (cleanupDm) { 435 Devmapper::destroy(idHash); 436 } 437 Loop::destroyByDevice(loopDevice); 438 unlink(asecFileName); 439 return -1; 440 } 441 } 442 443 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) { 452 SLOGE("ASEC FAT mount failed (%s)", strerror(errno)); 453 if (cleanupDm) { 454 Devmapper::destroy(idHash); 455 } 456 Loop::destroyByDevice(loopDevice); 457 unlink(asecFileName); 458 return -1; 459 } 460 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 } 471 } else { 472 SLOGI("Created raw secure container %s (no filesystem)", id); 473 } 474 475 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC)); 476 return 0; 477 } 478 479 int VolumeManager::finalizeAsec(const char *id) { 480 char asecFileName[255]; 481 char loopDevice[255]; 482 char mountPoint[255]; 483 484 if (findAsec(id, asecFileName, sizeof(asecFileName))) { 485 SLOGE("Couldn't find ASEC %s", id); 486 return -1; 487 } 488 489 char idHash[33]; 490 if (!asecHash(id, idHash, sizeof(idHash))) { 491 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); 492 return -1; 493 } 494 495 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) { 496 SLOGE("Unable to finalize %s (%s)", id, strerror(errno)); 497 return -1; 498 } 499 500 unsigned int nr_sec = 0; 501 struct asec_superblock sb; 502 503 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) { 504 return -1; 505 } 506 507 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 } 512 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) { 521 SLOGE("ASEC finalize mount failed (%s)", strerror(errno)); 522 return -1; 523 } 524 525 if (mDebug) { 526 SLOGD("ASEC %s finalized", id); 527 } 528 return 0; 529 } 530 531 int 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 564 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 } 569 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) { 612 result |= fchmod(fd, 0755); 613 } else if (ftsent->fts_info & FTS_F) { 614 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 647 int VolumeManager::renameAsec(const char *id1, const char *id2) { 648 char asecFilename1[255]; 649 char *asecFilename2; 650 char mountPoint[255]; 651 652 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); 660 661 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 667 if (isMountpointMounted(mountPoint)) { 668 SLOGW("Rename attempt when src mounted"); 669 errno = EBUSY; 670 goto out_err; 671 } 672 673 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 679 if (isMountpointMounted(mountPoint)) { 680 SLOGW("Rename attempt when dst mounted"); 681 errno = EBUSY; 682 goto out_err; 683 } 684 685 if (!access(asecFilename2, F_OK)) { 686 SLOGE("Rename attempt when dst exists"); 687 errno = EADDRINUSE; 688 goto out_err; 689 } 690 691 if (rename(asecFilename1, asecFilename2)) { 692 SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno)); 693 goto out_err; 694 } 695 696 free(asecFilename2); 697 return 0; 698 699 out_err: 700 free(asecFilename2); 701 return -1; 702 } 703 704 #define UNMOUNT_RETRIES 5 705 #define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000) 706 int VolumeManager::unmountAsec(const char *id, bool force) { 707 char asecFileName[255]; 708 char mountPoint[255]; 709 710 if (findAsec(id, asecFileName, sizeof(asecFileName))) { 711 SLOGE("Couldn't find ASEC %s", id); 712 return -1; 713 } 714 715 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 } 720 721 char idHash[33]; 722 if (!asecHash(id, idHash, sizeof(idHash))) { 723 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); 724 return -1; 725 } 726 727 return unmountLoopImage(id, idHash, asecFileName, mountPoint, force); 728 } 729 730 int VolumeManager::unmountObb(const char *fileName, bool force) { 731 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 739 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 } 744 745 return unmountLoopImage(fileName, idHash, fileName, mountPoint, force); 746 } 747 748 int VolumeManager::unmountLoopImage(const char *id, const char *idHash, 749 const char *fileName, const char *mountPoint, bool force) { 750 if (!isMountpointMounted(mountPoint)) { 751 SLOGE("Unmount request for %s when not mounted", id); 752 errno = ENOENT; 753 return -1; 754 } 755 756 int i, rc; 757 for (i = 1; i <= UNMOUNT_RETRIES; i++) { 758 rc = umount(mountPoint); 759 if (!rc) { 760 break; 761 } 762 if (rc && (errno == EINVAL || errno == ENOENT)) { 763 SLOGI("Container %s unmounted OK", id); 764 rc = 0; 765 break; 766 } 767 SLOGW("%s unmount attempt %d failed (%s)", 768 id, i, strerror(errno)); 769 770 int action = 0; // default is to just complain 771 772 if (force) { 773 if (i > (UNMOUNT_RETRIES - 2)) 774 action = 2; // SIGKILL 775 else if (i > (UNMOUNT_RETRIES - 3)) 776 action = 1; // SIGHUP 777 } 778 779 Process::killProcessesWithOpenFiles(mountPoint, action); 780 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS); 781 } 782 783 if (rc) { 784 errno = EBUSY; 785 SLOGE("Failed to unmount container %s (%s)", id, strerror(errno)); 786 return -1; 787 } 788 789 int retries = 10; 790 791 while(retries--) { 792 if (!rmdir(mountPoint)) { 793 break; 794 } 795 796 SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno)); 797 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS); 798 } 799 800 if (!retries) { 801 SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno)); 802 } 803 804 if (Devmapper::destroy(idHash) && errno != ENXIO) { 805 SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno)); 806 } 807 808 char loopDevice[255]; 809 if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) { 810 Loop::destroyByDevice(loopDevice); 811 } else { 812 SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno)); 813 } 814 815 AsecIdCollection::iterator it; 816 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) { 817 ContainerData* cd = *it; 818 if (!strcmp(cd->id, id)) { 819 free(*it); 820 mActiveContainers->erase(it); 821 break; 822 } 823 } 824 if (it == mActiveContainers->end()) { 825 SLOGW("mActiveContainers is inconsistent!"); 826 } 827 return 0; 828 } 829 830 int VolumeManager::destroyAsec(const char *id, bool force) { 831 char asecFileName[255]; 832 char mountPoint[255]; 833 834 if (findAsec(id, asecFileName, sizeof(asecFileName))) { 835 SLOGE("Couldn't find ASEC %s", id); 836 return -1; 837 } 838 839 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 } 844 845 if (isMountpointMounted(mountPoint)) { 846 if (mDebug) { 847 SLOGD("Unmounting container before destroy"); 848 } 849 if (unmountAsec(id, force)) { 850 SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno)); 851 return -1; 852 } 853 } 854 855 if (unlink(asecFileName)) { 856 SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno)); 857 return -1; 858 } 859 860 if (mDebug) { 861 SLOGD("ASEC %s destroyed", id); 862 } 863 return 0; 864 } 865 866 bool 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 884 int 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); 911 if ((written < 0) || (size_t(written) >= asecPathLen)) { 912 SLOGE("findAsec failed for %s: couldn't construct ASEC path", id); 913 free(asecName); 914 return -1; 915 } 916 } 917 918 free(asecName); 919 return 0; 920 } 921 922 int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) { 923 char asecFileName[255]; 924 char mountPoint[255]; 925 926 if (findAsec(id, asecFileName, sizeof(asecFileName))) { 927 SLOGE("Couldn't find ASEC %s", id); 928 return -1; 929 } 930 931 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 } 936 937 if (isMountpointMounted(mountPoint)) { 938 SLOGE("ASEC %s already mounted", id); 939 errno = EBUSY; 940 return -1; 941 } 942 943 char idHash[33]; 944 if (!asecHash(id, idHash, sizeof(idHash))) { 945 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); 946 return -1; 947 } 948 949 char loopDevice[255]; 950 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) { 951 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) { 952 SLOGE("ASEC loop device creation failed (%s)", strerror(errno)); 953 return -1; 954 } 955 if (mDebug) { 956 SLOGD("New loop device created at %s", loopDevice); 957 } 958 } else { 959 if (mDebug) { 960 SLOGD("Found active loopback for %s at %s", asecFileName, loopDevice); 961 } 962 } 963 964 char dmDevice[255]; 965 bool cleanupDm = false; 966 int fd; 967 unsigned int nr_sec = 0; 968 struct asec_superblock sb; 969 970 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) { 971 return -1; 972 } 973 974 if (mDebug) { 975 SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver); 976 } 977 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) { 978 SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver); 979 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 985 if (strcmp(key, "none")) { 986 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) { 987 if (Devmapper::create(idHash, loopDevice, key, nr_sec, 988 dmDevice, sizeof(dmDevice))) { 989 SLOGE("ASEC device mapping failed (%s)", strerror(errno)); 990 Loop::destroyByDevice(loopDevice); 991 return -1; 992 } 993 if (mDebug) { 994 SLOGD("New devmapper instance created at %s", dmDevice); 995 } 996 } else { 997 if (mDebug) { 998 SLOGD("Found active devmapper for %s at %s", asecFileName, dmDevice); 999 } 1000 } 1001 cleanupDm = true; 1002 } else { 1003 strcpy(dmDevice, loopDevice); 1004 } 1005 1006 if (mkdir(mountPoint, 0000)) { 1007 if (errno != EEXIST) { 1008 SLOGE("Mountpoint creation failed (%s)", strerror(errno)); 1009 if (cleanupDm) { 1010 Devmapper::destroy(idHash); 1011 } 1012 Loop::destroyByDevice(loopDevice); 1013 return -1; 1014 } 1015 } 1016 1017 /* 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 1030 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) { 1038 SLOGE("ASEC mount failed (%s)", strerror(errno)); 1039 if (cleanupDm) { 1040 Devmapper::destroy(idHash); 1041 } 1042 Loop::destroyByDevice(loopDevice); 1043 return -1; 1044 } 1045 1046 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC)); 1047 if (mDebug) { 1048 SLOGD("ASEC %s mounted", id); 1049 } 1050 return 0; 1051 } 1052 1053 Volume* VolumeManager::getVolumeForFile(const char *fileName) { 1054 VolumeCollection::iterator i; 1055 1056 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) { 1057 const char* mountPoint = (*i)->getFuseMountpoint(); 1058 if (!strncmp(fileName, mountPoint, strlen(mountPoint))) { 1059 return *i; 1060 } 1061 } 1062 1063 return NULL; 1064 } 1065 1066 /** 1067 * Mounts an image file <code>img</code>. 1068 */ 1069 int VolumeManager::mountObb(const char *img, const char *key, int ownerGid) { 1070 char mountPoint[255]; 1071 1072 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 1078 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 } 1083 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 1157 if (Fat::doMount(dmDevice, mountPoint, true, false, true, 0, ownerGid, 1158 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 1167 mActiveContainers->push_back(new ContainerData(strdup(img), OBB)); 1168 if (mDebug) { 1169 SLOGD("Image %s mounted", img); 1170 } 1171 return 0; 1172 } 1173 1174 int VolumeManager::mountVolume(const char *label) { 1175 Volume *v = lookupVolume(label); 1176 1177 if (!v) { 1178 errno = ENOENT; 1179 return -1; 1180 } 1181 1182 return v->mountVol(); 1183 } 1184 1185 int 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 1198 int loopDirLen = strlen(Volume::LOOPDIR); 1199 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 1230 int 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) { 1244 *enabled = false; 1245 } else { 1246 *enabled = true; 1247 } 1248 return 0; 1249 } 1250 1251 int 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 1274 if (v->getState() != Volume::State_Idle) { 1275 // You need to unmount manually befoe sharing 1276 errno = EBUSY; 1277 return -1; 1278 } 1279 1280 if (mVolManagerDisabled) { 1281 errno = EBUSY; 1282 return -1; 1283 } 1284 1285 dev_t d = v->getShareDevice(); 1286 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]; 1294 int written = snprintf(nodepath, 1295 sizeof(nodepath), "/dev/block/vold/%d:%d", 1296 MAJOR(d), MINOR(d)); 1297 1298 if ((written < 0) || (size_t(written) >= sizeof(nodepath))) { 1299 SLOGE("shareVolume failed: couldn't construct nodepath"); 1300 return -1; 1301 } 1302 1303 if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) { 1304 SLOGE("Unable to open ums lunfile (%s)", strerror(errno)); 1305 return -1; 1306 } 1307 1308 if (write(fd, nodepath, strlen(nodepath)) < 0) { 1309 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno)); 1310 close(fd); 1311 return -1; 1312 } 1313 1314 close(fd); 1315 v->handleVolumeShared(); 1316 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 } 1331 return 0; 1332 } 1333 1334 int 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 1352 int fd; 1353 if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) { 1354 SLOGE("Unable to open ums lunfile (%s)", strerror(errno)); 1355 return -1; 1356 } 1357 1358 char ch = 0; 1359 if (write(fd, &ch, 1) < 0) { 1360 SLOGE("Unable to write to ums lunfile (%s)", strerror(errno)); 1361 close(fd); 1362 return -1; 1363 } 1364 1365 close(fd); 1366 v->handleVolumeUnshared(); 1367 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 } 1377 return 0; 1378 } 1379 1380 extern "C" int vold_disableVol(const char *label) { 1381 VolumeManager *vm = VolumeManager::Instance(); 1382 vm->disableVolumeManager(); 1383 vm->unshareVolume(label, "ums"); 1384 return vm->unmountVolume(label, true, false); 1385 } 1386 1387 extern "C" int vold_getNumDirectVolumes(void) { 1388 VolumeManager *vm = VolumeManager::Instance(); 1389 return vm->getNumDirectVolumes(); 1390 } 1391 1392 int 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 1404 extern "C" int vold_getDirectVolumeList(struct volume_info *vol_list) { 1405 VolumeManager *vm = VolumeManager::Instance(); 1406 return vm->getDirectVolumeList(vol_list); 1407 } 1408 1409 int 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 1426 int VolumeManager::unmountVolume(const char *label, bool force, bool revert) { 1427 Volume *v = lookupVolume(label); 1428 1429 if (!v) { 1430 errno = ENOENT; 1431 return -1; 1432 } 1433 1434 if (v->getState() == Volume::State_NoMedia) { 1435 errno = ENODEV; 1436 return -1; 1437 } 1438 1439 if (v->getState() != Volume::State_Mounted) { 1440 SLOGW("Attempt to unmount volume which isn't mounted (%d)\n", 1441 v->getState()); 1442 errno = EBUSY; 1443 return UNMOUNT_NOT_MOUNTED_ERR; 1444 } 1445 1446 cleanupAsec(v, force); 1447 1448 return v->unmountVol(force, revert); 1449 } 1450 1451 extern "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) 1465 int 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) + 1475 fpathconf(dirfd(d), _PC_NAME_MAX) + 1; 1476 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 1507 /* 1508 * Looks up a volume by it's label or mount-point 1509 */ 1510 Volume *VolumeManager::lookupVolume(const char *label) { 1511 VolumeCollection::iterator i; 1512 1513 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) { 1514 if (label[0] == '/') { 1515 if (!strcmp(label, (*i)->getFuseMountpoint())) 1516 return (*i); 1517 } else { 1518 if (!strcmp(label, (*i)->getLabel())) 1519 return (*i); 1520 } 1521 } 1522 return NULL; 1523 } 1524 1525 bool 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"))) { 1534 SLOGE("Error opening /proc/mounts (%s)", strerror(errno)); 1535 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 } 1545 } 1546 1547 fclose(fp); 1548 return false; 1549 } 1550 1551 int VolumeManager::cleanupAsec(Volume *v, bool force) { 1552 int rc = unmountAllAsecsInDir(Volume::SEC_ASECDIR_EXT); 1553 1554 AsecIdCollection toUnmount; 1555 // Find the remaining OBB files that are on external storage. 1556 for (AsecIdCollection::iterator it = mActiveContainers->begin(); it != mActiveContainers->end(); 1557 ++it) { 1558 ContainerData* cd = *it; 1559 1560 if (cd->type == ASEC) { 1561 // nothing 1562 } else if (cd->type == OBB) { 1563 if (v == getVolumeForFile(cd->id)) { 1564 toUnmount.push_back(cd); 1565 } 1566 } else { 1567 SLOGE("Unknown container type %d!", cd->type); 1568 } 1569 } 1570 1571 for (AsecIdCollection::iterator it = toUnmount.begin(); it != toUnmount.end(); ++it) { 1572 ContainerData *cd = *it; 1573 SLOGI("Unmounting ASEC %s (dependant on %s)", cd->id, v->getFuseMountpoint()); 1574 if (unmountObb(cd->id, force)) { 1575 SLOGE("Failed to unmount OBB %s (%s)", cd->id, strerror(errno)); 1576 rc = -1; 1577 } 1578 } 1579 1580 return rc; 1581 } 1582 1583 int VolumeManager::mkdirs(char* path) { 1584 // Require that path lives under a volume we manage 1585 const char* emulated_source = getenv("EMULATED_STORAGE_SOURCE"); 1586 const char* root = NULL; 1587 if (!strncmp(path, emulated_source, strlen(emulated_source))) { 1588 root = emulated_source; 1589 } else { 1590 Volume* vol = getVolumeForFile(path); 1591 if (vol) { 1592 root = vol->getMountpoint(); 1593 } 1594 } 1595 1596 if (!root) { 1597 SLOGE("Failed to find volume for %s", path); 1598 return -EINVAL; 1599 } 1600 1601 /* fs_mkdirs() does symlink checking and relative path enforcement */ 1602 return fs_mkdirs(path, 0700); 1603 } 1604