int icusb_storage_do_unmomunt() { int ret = 0; if(isMountpointMounted("/mnt/udisk/folder1")) { icusb_print(PRINT_WARN, "[ICUSB][INFO] ====> icusb_storage_do_unmomunt1 .\n"); ret = icusb_do_exec(vdc_cmd, unmount_stor1_argv) ; } icusb_print(PRINT_WARN, "[ICUSB][INFO] unmomunt icusb_storage1, return %d \n", ret); if(isMountpointMounted("/mnt/udisk/folder2")) { icusb_print(PRINT_WARN, "[ICUSB][INFO] ====> icusb_storage_do_unmomunt2 .\n"); if(ret == 0) ret = icusb_do_exec(vdc_cmd, unmount_stor2_argv) ; } icusb_print(PRINT_WARN, "[ICUSB][INFO] unmomunt icusb_storage2, return %d \n", ret); icusb_print(PRINT_WARN, "[ICUSB][INFO] <==== icusb_storage_do_unmomunt\n"); return ret ; }
int VolumeManager::renameAsec(const char *id1, const char *id2) { char asecFilename1[255]; char *asecFilename2; char mountPoint[255]; const char *dir; if (findAsec(id1, asecFilename1, sizeof(asecFilename1), &dir)) { SLOGE("Couldn't find ASEC %s", id1); return -1; } asprintf(&asecFilename2, "%s/%s.asec", dir, id2); int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1); if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { SLOGE("Rename failed: couldn't construct mountpoint"); goto out_err; } if (isMountpointMounted(mountPoint)) { SLOGW("Rename attempt when src mounted"); errno = EBUSY; goto out_err; } written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2); if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { SLOGE("Rename failed: couldn't construct mountpoint2"); goto out_err; } if (isMountpointMounted(mountPoint)) { SLOGW("Rename attempt when dst mounted"); errno = EBUSY; goto out_err; } if (!access(asecFilename2, F_OK)) { SLOGE("Rename attempt when dst exists"); errno = EADDRINUSE; goto out_err; } if (rename(asecFilename1, asecFilename2)) { SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno)); goto out_err; } free(asecFilename2); return 0; out_err: free(asecFilename2); return -1; }
int VolumeManager::destroyAsec(const char *id, bool force) { char asecFileName[255]; char mountPoint[255]; if (findAsec(id, asecFileName, sizeof(asecFileName))) { SLOGE("Couldn't find ASEC %s", id); return -1; } int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id); if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { SLOGE("ASEC destroy failed for %s: couldn't construct mountpoint", id); return -1; } if (isMountpointMounted(mountPoint)) { if (mDebug) { SLOGD("Unmounting container before destroy"); } if (unmountAsec(id, force)) { SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno)); return -1; } } if (unlink(asecFileName)) { SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno)); return -1; } if (mDebug) { SLOGD("ASEC %s destroyed", id); } return 0; }
int VolumeManager::destroyAsec(const char *id, bool force) { char asecFileName[255]; char mountPoint[255]; snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id); snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id); if (isMountpointMounted(mountPoint)) { if (mDebug) { SLOGD("Unmounting container before destroy"); } if (unmountAsec(id, force)) { SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno)); return -1; } } if (unlink(asecFileName)) { SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno)); return -1; } if (mDebug) { SLOGD("ASEC %s destroyed", id); } return 0; }
int Volume::formatVol() { if (getState() == Volume::State_NoMedia) { errno = ENODEV; return -1; } else if (getState() != Volume::State_Idle) { errno = EBUSY; return -1; } if (isMountpointMounted(getMountpoint())) { SLOGW("Volume is idle but appears to be mounted - fixing"); setState(Volume::State_Mounted); // mCurrentlyMountedKdev = XXX errno = EBUSY; return -1; } bool formatEntireDevice = (mPartIdx == -1); char devicePath[255]; dev_t diskNode = getDiskDevice(); dev_t partNode = MKDEV(MAJOR(diskNode), (formatEntireDevice ? 1 : mPartIdx)); setState(Volume::State_Formatting); int ret = -1; // Only initialize the MBR if we are formatting the entire device if (formatEntireDevice) { sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(diskNode), MINOR(diskNode)); if (initializeMbr(devicePath)) { SLOGE("Failed to initialize MBR (%s)", strerror(errno)); goto err; } } sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(partNode), MINOR(partNode)); if (mDebug) { SLOGI("Formatting volume %s (%s)", getLabel(), devicePath); } if (Fat::format(devicePath, 0)) { SLOGE("Failed to format (%s)", strerror(errno)); goto err; } ret = 0; err: setState(Volume::State_Idle); return ret; }
int VolumeManager::renameAsec(const char *id1, const char *id2) { char *asecFilename1; char *asecFilename2; char mountPoint[255]; asprintf(&asecFilename1, "%s/%s.asec", Volume::SEC_ASECDIR, id1); asprintf(&asecFilename2, "%s/%s.asec", Volume::SEC_ASECDIR, id2); snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1); if (isMountpointMounted(mountPoint)) { SLOGW("Rename attempt when src mounted"); errno = EBUSY; goto out_err; } snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2); if (isMountpointMounted(mountPoint)) { SLOGW("Rename attempt when dst mounted"); errno = EBUSY; goto out_err; } if (!access(asecFilename2, F_OK)) { SLOGE("Rename attempt when dst exists"); errno = EADDRINUSE; goto out_err; } if (rename(asecFilename1, asecFilename2)) { SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno)); goto out_err; } free(asecFilename1); free(asecFilename2); return 0; out_err: free(asecFilename1); free(asecFilename2); return -1; }
int Volume::formatVol() { if (getState() == Volume::State_NoMedia) { errno = ENODEV; return -1; } else if (getState() != Volume::State_Idle) { errno = EBUSY; return -1; } if (isMountpointMounted(getMountpoint())) { SLOGW("Volume is idle but appears to be mounted - fixing"); setState(Volume::State_Mounted); // mCurrentlyMountedKdev = XXX errno = EBUSY; return -1; } char devicePath[255]; dev_t diskNode = getDiskDevice(); dev_t partNode = MKDEV(MAJOR(diskNode), 1); // XXX: Hmmm sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(diskNode), MINOR(diskNode)); if (mDebug) { SLOGI("Formatting volume %s (%s)", getLabel(), devicePath); } setState(Volume::State_Formatting); if (initializeMbr(devicePath)) { SLOGE("Failed to initialize MBR (%s)", strerror(errno)); goto err; } sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(partNode), MINOR(partNode)); if (Fat::format(devicePath, 0)) { SLOGE("Failed to format (%s)", strerror(errno)); goto err; } setState(Volume::State_Idle); return 0; err: return -1; }
int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) { char asecFileName[255]; char mountPoint[255]; snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id); snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id); if (isMountpointMounted(mountPoint)) { SLOGE("ASEC %s already mounted", id); errno = EBUSY; return -1; } char idHash[33]; if (!asecHash(id, idHash, sizeof(idHash))) { SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); return -1; } char loopDevice[255]; if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) { if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) { SLOGE("ASEC loop device creation failed (%s)", strerror(errno)); return -1; } if (mDebug) { SLOGD("New loop device created at %s", loopDevice); } } else { if (mDebug) { SLOGD("Found active loopback for %s at %s", asecFileName, loopDevice); } } char dmDevice[255]; bool cleanupDm = false; int fd; unsigned int nr_sec = 0; if ((fd = open(loopDevice, O_RDWR)) < 0) { SLOGE("Failed to open loopdevice (%s)", strerror(errno)); Loop::destroyByDevice(loopDevice); return -1; } if (ioctl(fd, BLKGETSIZE, &nr_sec)) { SLOGE("Failed to get loop size (%s)", strerror(errno)); Loop::destroyByDevice(loopDevice); close(fd); return -1; } /* * Validate superblock */ struct asec_superblock sb; memset(&sb, 0, sizeof(sb)); if (lseek(fd, ((nr_sec-1) * 512), SEEK_SET) < 0) { SLOGE("lseek failed (%s)", strerror(errno)); close(fd); Loop::destroyByDevice(loopDevice); return -1; } if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) { SLOGE("superblock read failed (%s)", strerror(errno)); close(fd); Loop::destroyByDevice(loopDevice); return -1; } close(fd); if (mDebug) { SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver); } if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) { SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver); Loop::destroyByDevice(loopDevice); errno = EMEDIUMTYPE; return -1; } nr_sec--; // We don't want the devmapping to extend onto our superblock if (strcmp(key, "none")) { if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) { if (Devmapper::create(idHash, loopDevice, key, nr_sec, dmDevice, sizeof(dmDevice))) { SLOGE("ASEC device mapping failed (%s)", strerror(errno)); Loop::destroyByDevice(loopDevice); return -1; } if (mDebug) { SLOGD("New devmapper instance created at %s", dmDevice); } } else { if (mDebug) { SLOGD("Found active devmapper for %s at %s", asecFileName, dmDevice); } } cleanupDm = true; } else { strcpy(dmDevice, loopDevice); } if (mkdir(mountPoint, 0777)) { if (errno != EEXIST) { SLOGE("Mountpoint creation failed (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); return -1; } } if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0, 0222, false)) { // 0227, false)) { SLOGE("ASEC mount failed (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); return -1; } mActiveContainers->push_back(new ContainerData(strdup(id), ASEC)); if (mDebug) { SLOGD("ASEC %s mounted", id); } return 0; }
int Volume::mountVol() { dev_t deviceNodes[4]; int n, i, rc = 0; char errmsg[255]; if (getState() == Volume::State_NoMedia) { snprintf(errmsg, sizeof(errmsg), "Volume %s %s mount failed - no media", getLabel(), getMountpoint()); mVm->getBroadcaster()->sendBroadcast( ResponseCode::VolumeMountFailedNoMedia, errmsg, false); errno = ENODEV; return -1; } else if (getState() != Volume::State_Idle) { errno = EBUSY; return -1; } if (isMountpointMounted(getMountpoint())) { SLOGW("Volume is idle but appears to be mounted - fixing"); setState(Volume::State_Mounted); // mCurrentlyMountedKdev = XXX return 0; } n = getDeviceNodes((dev_t *) &deviceNodes, 4); if (!n) { SLOGE("Failed to get device nodes (%s)\n", strerror(errno)); return -1; } for (i = 0; i < n; i++) { char devicePath[255]; sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(deviceNodes[i]), MINOR(deviceNodes[i])); SLOGI("%s being considered for volume %s\n", devicePath, getLabel()); errno = 0; setState(Volume::State_Checking); if (Fat::check(devicePath)) { if (errno == ENODATA) { SLOGW("%s does not contain a FAT filesystem\n", devicePath); continue; } errno = EIO; /* Badness - abort the mount */ SLOGE("%s failed FS checks (%s)", devicePath, strerror(errno)); setState(Volume::State_Idle); return -1; } /* * Mount the device on our internal staging mountpoint so we can * muck with it before exposing it to non priviledged users. */ errno = 0; if (Fat::doMount(devicePath, "/mnt/secure/staging", false, false, false, 1000, 1015, 0702, true)) { SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno)); continue; } SLOGI("Device %s, target %s mounted @ /mnt/secure/staging", devicePath, getMountpoint()); protectFromAutorunStupidity(); if (createBindMounts()) { SLOGE("Failed to create bindmounts (%s)", strerror(errno)); umount("/mnt/secure/staging"); setState(Volume::State_Idle); return -1; } /* * Now that the bindmount trickery is done, atomically move the * whole subtree to expose it to non priviledged users. */ if (doMoveMount("/mnt/secure/staging", getMountpoint(), false)) { SLOGE("Failed to move mount (%s)", strerror(errno)); umount("/mnt/secure/staging"); setState(Volume::State_Idle); return -1; } setState(Volume::State_Mounted); mCurrentlyMountedKdev = deviceNodes[i]; return 0; } SLOGE("Volume %s found no suitable devices for mounting :(\n", getLabel()); setState(Volume::State_Idle); return -1; }
/** * Mounts an image file <code>img</code>. */ int VolumeManager::mountObb(const char *img, const char *key, int ownerGid) { char mountPoint[255]; char idHash[33]; if (!asecHash(img, idHash, sizeof(idHash))) { SLOGE("Hash of '%s' failed (%s)", img, strerror(errno)); return -1; } int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash); if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { SLOGE("OBB mount failed: couldn't construct mountpoint %s", img); return -1; } if (isMountpointMounted(mountPoint)) { SLOGE("Image %s already mounted", img); errno = EBUSY; return -1; } char loopDevice[255]; if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) { if (Loop::create(idHash, img, loopDevice, sizeof(loopDevice))) { SLOGE("Image loop device creation failed (%s)", strerror(errno)); return -1; } if (mDebug) { SLOGD("New loop device created at %s", loopDevice); } } else { if (mDebug) { SLOGD("Found active loopback for %s at %s", img, loopDevice); } } char dmDevice[255]; bool cleanupDm = false; int fd; unsigned int nr_sec = 0; if ((fd = open(loopDevice, O_RDWR)) < 0) { SLOGE("Failed to open loopdevice (%s)", strerror(errno)); Loop::destroyByDevice(loopDevice); return -1; } if (ioctl(fd, BLKGETSIZE, &nr_sec)) { SLOGE("Failed to get loop size (%s)", strerror(errno)); Loop::destroyByDevice(loopDevice); close(fd); return -1; } close(fd); if (strcmp(key, "none")) { if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) { if (Devmapper::create(idHash, loopDevice, key, nr_sec, dmDevice, sizeof(dmDevice))) { SLOGE("ASEC device mapping failed (%s)", strerror(errno)); Loop::destroyByDevice(loopDevice); return -1; } if (mDebug) { SLOGD("New devmapper instance created at %s", dmDevice); } } else { if (mDebug) { SLOGD("Found active devmapper for %s at %s", img, dmDevice); } } cleanupDm = true; } else { strcpy(dmDevice, loopDevice); } if (mkdir(mountPoint, 0755)) { if (errno != EEXIST) { SLOGE("Mountpoint creation failed (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); return -1; } } if (Fat::doMount(dmDevice, mountPoint, true, false, true, 0, ownerGid, 0227, false)) { SLOGE("Image mount failed (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); return -1; } mActiveContainers->push_back(new ContainerData(strdup(img), OBB)); if (mDebug) { SLOGD("Image %s mounted", img); } return 0; }
int VolumeManager::unmountLoopImage(const char *id, const char *idHash, const char *fileName, const char *mountPoint, bool force) { if (!isMountpointMounted(mountPoint)) { SLOGE("Unmount request for %s when not mounted", id); errno = ENOENT; return -1; } int i, rc; for (i = 1; i <= UNMOUNT_RETRIES; i++) { rc = umount(mountPoint); if (!rc) { break; } if (rc && (errno == EINVAL || errno == ENOENT)) { SLOGI("Container %s unmounted OK", id); rc = 0; break; } SLOGW("%s unmount attempt %d failed (%s)", id, i, strerror(errno)); int action = 0; // default is to just complain if (force) { if (i > (UNMOUNT_RETRIES - 2)) action = 2; // SIGKILL else if (i > (UNMOUNT_RETRIES - 3)) action = 1; // SIGHUP } Process::killProcessesWithOpenFiles(mountPoint, action); usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS); } if (rc) { errno = EBUSY; SLOGE("Failed to unmount container %s (%s)", id, strerror(errno)); return -1; } int retries = 10; while(retries--) { if (!rmdir(mountPoint)) { break; } SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno)); usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS); } if (!retries) { SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno)); } if (Devmapper::destroy(idHash) && errno != ENXIO) { SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno)); } char loopDevice[255]; if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) { Loop::destroyByDevice(loopDevice); } else { SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno)); } AsecIdCollection::iterator it; for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) { ContainerData* cd = *it; if (!strcmp(cd->id, id)) { free(*it); mActiveContainers->erase(it); break; } } if (it == mActiveContainers->end()) { SLOGW("mActiveContainers is inconsistent!"); } return 0; }
void DirectVolume::handlePartitionAdded(const char *devpath, NetlinkEvent *evt) { bool is_udisk = false; int major = atoi(evt->findParam("MAJOR")); int minor = atoi(evt->findParam("MINOR")); int part_num; const char *tmp = evt->findParam("PARTN"); if (tmp) { part_num = atoi(tmp); } else { SLOGW("Kernel block uevent missing 'PARTN'"); part_num = 1; } if (part_num > MAX_PARTITIONS || part_num < 1) { SLOGE("Invalid 'PARTN' value"); return; } if(strstr(devpath,"pci")&&strstr(devpath,"sd")) is_udisk = true; if (isMountpointMounted(getMountpoint())|| (is_udisk&&(getState()!=Volume::State_Pending))) { SLOGD("not the first udisk in handlePartitionAdded %d %d\n",major,minor); mountExtraPartition(major,minor); return; } if (part_num > mDiskNumParts) { mDiskNumParts = part_num; } if (major != mDiskMajor) { SLOGE("Partition '%s' has a different major than its disk!", devpath); return; } #ifdef PARTITION_DEBUG SLOGD("Dv:partAdd: part_num = %d, minor = %d\n", part_num, minor); #endif if (part_num >= MAX_PARTITIONS) { SLOGE("Dv:partAdd: ignoring part_num = %d (max: %d)\n", part_num, MAX_PARTITIONS-1); } else { mPartMinors[part_num -1] = minor; } if(mPendingPartMap>1) mPendingPartMap = mPendingPartMap>>1; //mPendingPartMap &= ~(1 << part_num); if (mPendingPartMap==0x1) { #ifdef PARTITION_DEBUG SLOGD("Dv:partAdd: Got all partitions - ready to rock!"); #endif if (getState() != Volume::State_Formatting) { setState(Volume::State_Idle); if (mRetryMount == true) { mRetryMount = false; mountVol(); } } } else { #ifdef PARTITION_DEBUG SLOGD("Dv:partAdd: pending mask now = 0x%x", mPendingPartMap); #endif } }
int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) { char asecFileName[255]; char mountPoint[255]; if (!isLegalAsecId(id)) { SLOGE("mountAsec: Invalid asec id \"%s\"", id); errno = EINVAL; return -1; } if (findAsec(id, asecFileName, sizeof(asecFileName))) { SLOGE("Couldn't find ASEC %s", id); return -1; } int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id); if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) { SLOGE("ASEC mount failed: couldn't construct mountpoint %s", id); return -1; } if (isMountpointMounted(mountPoint)) { SLOGE("ASEC %s already mounted", id); errno = EBUSY; return -1; } char idHash[33]; if (!asecHash(id, idHash, sizeof(idHash))) { SLOGE("Hash of '%s' failed (%s)", id, strerror(errno)); return -1; } char loopDevice[255]; if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) { if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) { SLOGE("ASEC loop device creation failed (%s)", strerror(errno)); return -1; } if (mDebug) { SLOGD("New loop device created at %s", loopDevice); } } else { if (mDebug) { SLOGD("Found active loopback for %s at %s", asecFileName, loopDevice); } } char dmDevice[255]; bool cleanupDm = false; unsigned int nr_sec = 0; struct asec_superblock sb; if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) { return -1; } if (mDebug) { SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver); } if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) { SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver); Loop::destroyByDevice(loopDevice); errno = EMEDIUMTYPE; return -1; } nr_sec--; // We don't want the devmapping to extend onto our superblock if (strcmp(key, "none")) { if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) { if (Devmapper::create(idHash, loopDevice, key, nr_sec, dmDevice, sizeof(dmDevice))) { SLOGE("ASEC device mapping failed (%s)", strerror(errno)); Loop::destroyByDevice(loopDevice); return -1; } if (mDebug) { SLOGD("New devmapper instance created at %s", dmDevice); } } else { if (mDebug) { SLOGD("Found active devmapper for %s at %s", asecFileName, dmDevice); } } cleanupDm = true; } else { strcpy(dmDevice, loopDevice); } if (mkdir(mountPoint, 0000)) { if (errno != EEXIST) { SLOGE("Mountpoint creation failed (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); return -1; } } /* * The device mapper node needs to be created. Sometimes it takes a * while. Wait for up to 1 second. We could also inspect incoming uevents, * but that would take more effort. */ int tries = 25; while (tries--) { if (!access(dmDevice, F_OK) || errno != ENOENT) { break; } usleep(40 * 1000); } int result; if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) { result = Ext4::doMount(dmDevice, mountPoint, true, false, true, false); } else { result = Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0, 0222, false); } if (result) { SLOGE("ASEC mount failed (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); } Loop::destroyByDevice(loopDevice); return -1; } mActiveContainers->push_back(new ContainerData(strdup(id), ASEC)); if (mDebug) { SLOGD("ASEC %s mounted", id); } return 0; }
int Volume::mountVol() { dev_t deviceNodes[MAX_SUP_PART]; // dev_t deviceNodes[4]; int n, i, curState, rc = 0; char errmsg[255]; const char* externalStorage = getenv("EXTERNAL_STORAGE"); bool primaryStorage = externalStorage && !strcmp(getMountpoint(), externalStorage); char decrypt_state[PROPERTY_VALUE_MAX]; char crypto_state[PROPERTY_VALUE_MAX]; char encrypt_progress[PROPERTY_VALUE_MAX]; int flags; property_get("vold.decrypt", decrypt_state, ""); property_get("vold.encrypt_progress", encrypt_progress, ""); /* Don't try to mount the volumes if we have not yet entered the disk password * or are in the process of encrypting. */ if ((getState() == Volume::State_NoMedia) || ((!strcmp(decrypt_state, "1") || encrypt_progress[0]) && primaryStorage)) { snprintf(errmsg, sizeof(errmsg), "Volume %s %s mount failed - no media", getLabel(), getMountpoint()); mVm->getBroadcaster()->sendBroadcast( ResponseCode::VolumeMountFailedNoMedia, errmsg, false); errno = ENODEV; return -1; } else if (getState() != Volume::State_Idle) { errno = EBUSY; if (getState() == Volume::State_Pending) { mRetryMount = true; } return -1; } if (isMountpointMounted(getMountpoint())) { SLOGW("Volume is idle but appears to be mounted - fixing"); setState(Volume::State_Mounted); // mCurrentlyMountedKdev = XXX return 0; } #ifdef MTK_SHARED_SDCARD if (IsEmmcStorage()) { setState(Volume::State_Mounted); return 0; } #endif // n = getDeviceNodes((dev_t *) &deviceNodes, 4); n = getDeviceNodes((dev_t *) &deviceNodes, MAX_SUP_PART); if (!n) { SLOGE("Failed to get device nodes (%s)\n", strerror(errno)); return -1; } SLOGD("Found %d device nodes", n); #ifdef MTK_SD_REINIT_SUPPORT if (!IsEmmcStorage()) { SLOGD("Reinit SD card"); if (mVm->reinitExternalSD()){ SLOGD("Fail: reinitExternalSD()"); } } #endif /* If we're running encrypted, and the volume is marked as encryptable and nonremovable, * and vold is asking to mount the primaryStorage device, then we need to decrypt * that partition, and update the volume object to point to it's new decrypted * block device */ property_get("ro.crypto.state", crypto_state, ""); flags = getFlags(); if (primaryStorage && ((flags & (VOL_NONREMOVABLE | VOL_ENCRYPTABLE))==(VOL_NONREMOVABLE | VOL_ENCRYPTABLE)) && !strcmp(crypto_state, "encrypted") && !isDecrypted()) { char new_sys_path[MAXPATHLEN]; char nodepath[256]; int new_major, new_minor; if (n != 1) { /* We only expect one device node returned when mounting encryptable volumes */ SLOGE("Too many device nodes returned when mounting %d\n", getMountpoint()); return -1; } if (cryptfs_setup_volume(getLabel(), MAJOR(deviceNodes[0]), MINOR(deviceNodes[0]), new_sys_path, sizeof(new_sys_path), &new_major, &new_minor)) { SLOGE("Cannot setup encryption mapping for %d\n", getMountpoint()); return -1; } /* We now have the new sysfs path for the decrypted block device, and the * majore and minor numbers for it. So, create the device, update the * path to the new sysfs path, and continue. */ snprintf(nodepath, sizeof(nodepath), "/dev/block/vold/%d:%d", new_major, new_minor); if (createDeviceNode(nodepath, new_major, new_minor)) { SLOGE("Error making device node '%s' (%s)", nodepath, strerror(errno)); } // Todo: Either create sys filename from nodepath, or pass in bogus path so // vold ignores state changes on this internal device. updateDeviceInfo(nodepath, new_major, new_minor); /* Get the device nodes again, because they just changed */ n = getDeviceNodes((dev_t *) &deviceNodes, MAX_SUP_PART); if (!n) { SLOGE("Failed to get device nodes (%s)\n", strerror(errno)); return -1; } } for (i = 0; i < n; i++) { char devicePath[255]; sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(deviceNodes[i]), MINOR(deviceNodes[i])); if (deviceNodes[i] == (dev_t)(-1)) { SLOGE("Partition '%s' is invalid dev_t. Skip mounting!", devicePath); continue; } SLOGI("%s being considered for volume %s\n", devicePath, getLabel()); errno = 0; setState(Volume::State_Checking); /* * If FS check failed, we should move on to next partition * instead of returning an error */ __CHECK_FAT_AGAIN: if (Fat::check(devicePath)) { #if 0 if (errno == ENODATA) { SLOGW("%s does not contain a FAT filesystem\n", devicePath); continue; } errno = EIO; /* Badness - abort the mount */ SLOGE("%s failed FS checks (%s)", devicePath, strerror(errno)); setState(Volume::State_Idle); return -1; #else #ifdef MTK_EMMC_SUPPORT if ( mVm->isFirstBoot() && IsEmmcStorage()) { SLOGI("** This is first boot and internal sd is not formatted. Try to format it. (%s)\n", devicePath); if (Fat::format(devicePath, 0)) { SLOGE("Failed to format (%s)", strerror(errno)); } else { SLOGI("Format successfully. (%s)\n", devicePath); property_set("persist.first_boot", "0"); goto __CHECK_FAT_AGAIN; } } #endif SLOGW("%s failed FS checks, move on to next partition", devicePath); continue; #endif } #ifdef MTK_EMMC_SUPPORT else { if ( mVm->isFirstBoot() && IsEmmcStorage()) { property_set("persist.first_boot", "0"); } } #endif /* * Mount the device on our internal staging mountpoint so we can * muck with it before exposing it to non priviledged users. */ errno = 0; int gid; if (primaryStorage) { // Special case the primary SD card. // For this we grant write access to the SDCARD_RW group. gid = AID_SDCARD_RW; } else { // For secondary external storage we keep things locked up. /* Note: Change the google default setting from AID_MEDIA_RW to AID_SDCARD_RW. */ gid = AID_SDCARD_RW; } if (Fat::doMount(devicePath, "/mnt/secure/staging", false, false, false, AID_SYSTEM, gid, 0702, true)) { SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno)); // kill the process anyway Process::killProcessesWithOpenFiles("/mnt/secure/staging", 2); continue; } SLOGI("Device %s, target %s mounted @ /mnt/secure/staging", devicePath, getMountpoint()); SLOGI("PrimaryStory = %d, externalStorage = %s", primaryStorage, externalStorage); protectFromAutorunStupidity(); // only create android_secure on primary storage if (primaryStorage && createBindMounts()) { SLOGE("Failed to create bindmounts (%s)", strerror(errno)); umount("/mnt/secure/staging"); setState(Volume::State_Idle); return -1; } /* * Now that the bindmount trickery is done, atomically move the * whole subtree to expose it to non priviledged users. */ if (doMoveMount("/mnt/secure/staging", getMountpoint(), false)) { SLOGE("Failed to move mount (%s)", strerror(errno)); umount("/mnt/secure/staging"); setState(Volume::State_Idle); return -1; } setState(Volume::State_Mounted); mCurrentlyMountedKdev = deviceNodes[i]; return 0; } SLOGE("Volume %s found no suitable devices for mounting :(\n", getLabel()); spin_lock(&mStateLock); curState = getState(); if ((curState != Volume::State_NoMedia) && (curState != Volume::State_Mounted)) setState(Volume::State_Idle); if(curState == Volume::State_Mounted) { spin_unlock(&mStateLock); return 0; } spin_unlock(&mStateLock); return -1; }
int Volume::formatVol(bool wipe) { dev_t deviceNodes[DirectVolume::MAX_PARTITIONS]; bool isForceFat32 = false; if (getState() == Volume::State_NoMedia) { errno = ENODEV; return -1; } else if (getState() != Volume::State_Idle) { errno = EBUSY; return -1; } #ifdef MTK_SHARED_SDCARD if(IsEmmcStorage()){ SLOGE("It is not allowed to format internal SDCARD with MTK_SHARED_SDCARD enabled"); errno = -EPERM; return errno; } #endif if (isMountpointMounted(getMountpoint())) { SLOGW("Volume is idle but appears to be mounted - fixing"); setState(Volume::State_Mounted); // mCurrentlyMountedKdev = XXX errno = EBUSY; return -1; } SLOGI("mDiskNumParts = %d\n", getDeviceNumParts()); bool formatEntireDevice = (mPartIdx == -1); char devicePath[255]; dev_t diskNode = getDiskDevice(); dev_t partNode = MKDEV(MAJOR(diskNode), MINOR(diskNode) + (formatEntireDevice ? 1 : mPartIdx)); setState(Volume::State_Formatting); int ret = -1; #ifdef MTK_MULTI_PARTITION_MOUNT_ONLY_SUPPORT char *otgNodePath = getOtgNodePath(); if (0 == strcmp(getLabel(), "usbotg")) { if (NULL == otgNodePath) { SLOGE("usbotg: Volume formatVol otgNodePath is NULL"); goto err; } SLOGD("usbotg: Volume formatVol otgNodePath = %s", otgNodePath); // Only initialize the MBR if we are formatting the entire device if (formatEntireDevice) { SLOGI("usbotg: Volume formatVol call initializeMbr().\n"); if (initializeMbr(otgNodePath)) { SLOGE("usbotg: Volume formatVol failed to initialize MBR (%s)", strerror(errno)); goto err; } SLOGI("usbotg: Volume formatVol exit initializeMbr().\n"); } if (Fat::format(otgNodePath, 0, wipe, isForceFat32)) { SLOGE("usbotg: Volume formatVol Failed to format (%s)", strerror(errno)); goto err; } } else { // Only initialize the MBR if we are formatting the entire device if (formatEntireDevice) { sprintf(devicePath, "/dev/block/vold/%d:%d", major(diskNode), minor(diskNode)); SLOGI("Call initializeMbr().\n"); if (initializeMbr(devicePath)) { SLOGE("Failed to initialize MBR (%s)", strerror(errno)); goto err; } SLOGI("Exit initializeMbr().\n"); } sprintf(devicePath, "/dev/block/vold/%d:%d", major(partNode), minor(partNode)); if (mDebug) { SLOGI("Formatting volume %s (%s)", getLabel(), devicePath); } #ifdef MTK_ICUSB_SUPPORT if(!strcmp(getLabel(), "icusb1") || !strcmp(getLabel(), "icusb2")){ isForceFat32 = true; } #endif if (Fat::format(devicePath, 0, wipe, isForceFat32)) { SLOGE("Failed to format (%s)", strerror(errno)); goto err; } } #else { // Only initialize the MBR if we are formatting the entire device if (formatEntireDevice) { sprintf(devicePath, "/dev/block/vold/%d:%d", major(diskNode), minor(diskNode)); SLOGI("Call initializeMbr().\n"); if (initializeMbr(devicePath)) { SLOGE("Failed to initialize MBR (%s)", strerror(errno)); goto err; } } sprintf(devicePath, "/dev/block/vold/%d:%d", major(partNode), minor(partNode)); if (mDebug) { SLOGI("Formatting volume %s (%s)", getLabel(), devicePath); } #ifdef MTK_ICUSB_SUPPORT if(!strcmp(getLabel(), "icusb1") || !strcmp(getLabel(), "icusb2")){ isForceFat32 = true; } #endif if (Fat::format(devicePath, 0, wipe, isForceFat32)) { SLOGE("Failed to format (%s)", strerror(errno)); goto err; } } #endif ret = 0; err: setState(Volume::State_Idle); return ret; }
int Volume::formatVol() { if (getState() == Volume::State_NoMedia) { errno = ENODEV; return -1; } else if (getState() != Volume::State_Idle) { errno = EBUSY; return -1; } if (isMountpointMounted(getMountpoint())) { SLOGW("Volume is idle but appears to be mounted - fixing"); setState(Volume::State_Mounted); // mCurrentlyMountedKdev = XXX errno = EBUSY; return -1; } bool formatEntireDevice = (mPartIdx == -1); char devicePath[255]; dev_t diskNode = getDiskDevice(); dev_t partNode = MKDEV(MAJOR(diskNode), (formatEntireDevice ? 1 : mPartIdx)); setState(Volume::State_Formatting); int ret = -1; // Only initialize the MBR if we are formatting the entire device if (formatEntireDevice) { sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(diskNode), MINOR(diskNode)); if (initializeMbr(devicePath)) { SLOGE("Failed to initialize MBR (%s)", strerror(errno)); goto err; } } sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(partNode), MINOR(partNode)); #ifdef VOLD_EMMC_SHARES_DEV_MAJOR // If emmc and sdcard share dev major number, vold may pick // incorrectly based on partition nodes alone, formatting // the wrong device. Use device nodes instead. dev_t deviceNodes; getDeviceNodes((dev_t *) &deviceNodes, 1); sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(deviceNodes), MINOR(deviceNodes)); #endif if (mDebug) { SLOGI("Formatting volume %s (%s)", getLabel(), devicePath); } if (Fat::format(devicePath, 0)) { SLOGE("Failed to format (%s)", strerror(errno)); goto err; } ret = 0; err: setState(Volume::State_Idle); return ret; }
int Volume::mountVol() { dev_t deviceNodes[DirectVolume::MAX_PARTITIONS]; int n, i, rc = 0, curState; char errmsg[255]; int flags = getFlags(); /* we igore the setting of "VOL_PROVIDES_ASEC". if the storage is primary, then we will handle "Asec" */ //bool providesAsec = (flags & VOL_PROVIDES_ASEC) != 0; const char* externalStorage = getenv("EXTERNAL_STORAGE"); bool providesAsec = externalStorage && !strcmp(getFuseMountpoint(), externalStorage); // TODO: handle "bind" style mounts, for emulated storage char decrypt_state[PROPERTY_VALUE_MAX]; char crypto_state[PROPERTY_VALUE_MAX]; char encrypt_progress[PROPERTY_VALUE_MAX]; if (mPreState != Volume::State_Shared && mVm->isSomeVolumeShared()) { SLOGI("Some volume is State_Shared, force to share current volume, %s \n", getLabel()); return mVm->shareVolume(getLabel(), "ums"); } property_get("vold.decrypt", decrypt_state, ""); property_get("vold.encrypt_progress", encrypt_progress, ""); #ifdef MTK_MULTI_PARTITION_MOUNT_ONLY_SUPPORT char *otgNodePath = getOtgNodePath(); #endif /* Don't try to mount the volumes if we have not yet entered the disk password * or are in the process of encrypting. */ if ((getState() == Volume::State_NoMedia) || ((!strcmp(decrypt_state, "trigger_restart_min_framework") || encrypt_progress[0]) && providesAsec)) { snprintf(errmsg, sizeof(errmsg), "Volume %s %s mount failed - no media", getLabel(), getFuseMountpoint()); mVm->getBroadcaster()->sendBroadcast( ResponseCode::VolumeMountFailedNoMedia, errmsg, false); errno = ENODEV; return -1; } else if (getState() != Volume::State_Idle) { errno = EBUSY; if (getState() == Volume::State_Pending) { mRetryMount = true; } return -1; } if (isMountpointMounted(getMountpoint())) { SLOGW("Volume is idle but appears to be mounted - fixing"); setState(Volume::State_Mounted); // mCurrentlyMountedKdev = XXX return 0; } #ifdef MTK_SHARED_SDCARD SLOGI("mountvol: IsEmmcStorage=%d", IsEmmcStorage()); if (IsEmmcStorage()) { property_set("ctl.start", "sdcard"); waitForServiceState("sdcard", "running"); setState(Volume::State_Mounted); return 0; } #endif n = getDeviceNodes((dev_t *) &deviceNodes, DirectVolume::MAX_PARTITIONS); if (!n) { SLOGE("Failed to get device nodes (%s)\n", strerror(errno)); return -1; } SLOGD("Found %d device nodes", n); #ifndef MTK_EMULATOR_SUPPORT if (!IsEmmcStorage() && !strncmp(getLabel(), "sdcard", 6)) { #ifdef MTK_FAT_ON_NAND if( -1 == mLoopDeviceIdx){ #endif SLOGD("Reinit SD card"); if (mVm->reinitExternalSD()){ SLOGE("Fail: reinitExternalSD()"); /* Card inserted but fail to reinit, there is something wrong with this card */ errno = EIO; return -1; } #ifdef MTK_FAT_ON_NAND } #endif } #endif /* If we're running encrypted, and the volume is marked as encryptable and nonremovable, * and also marked as providing Asec storage, then we need to decrypt * that partition, and update the volume object to point to it's new decrypted * block device */ property_get("ro.crypto.state", crypto_state, ""); if (providesAsec && ((flags & (VOL_NONREMOVABLE | VOL_ENCRYPTABLE))==(VOL_NONREMOVABLE | VOL_ENCRYPTABLE)) && !strcmp(crypto_state, "encrypted") && !isDecrypted()) { char new_sys_path[MAXPATHLEN]; char nodepath[256]; int new_major, new_minor; if (n != 1) { /* We only expect one device node returned when mounting encryptable volumes */ SLOGE("Too many device nodes returned when mounting %s\n", getMountpoint()); return -1; } if (cryptfs_setup_volume(getLabel(), MAJOR(deviceNodes[0]), MINOR(deviceNodes[0]), new_sys_path, sizeof(new_sys_path), &new_major, &new_minor)) { SLOGE("Cannot setup encryption mapping for %s\n", getMountpoint()); return -1; } #ifdef MTK_MULTI_PARTITION_MOUNT_ONLY_SUPPORT if (0 == strcmp(getLabel(), "usbotg")) { if (createDeviceNode(otgNodePath, new_major, new_minor)) { SLOGE("usbotg: Volume mountVol Error making device node '%s' (%s)", otgNodePath, strerror(errno)); } updateDeviceInfo(otgNodePath, new_major, new_minor); } else #endif /* We now have the new sysfs path for the decrypted block device, and the * majore and minor numbers for it. So, create the device, update the * path to the new sysfs path, and continue. */ { snprintf(nodepath, sizeof(nodepath), "/dev/block/vold/%d:%d", new_major, new_minor); if (createDeviceNode(nodepath, new_major, new_minor)) { SLOGE("Error making device node '%s' (%s)", nodepath, strerror(errno)); } // Todo: Either create sys filename from nodepath, or pass in bogus path so // vold ignores state changes on this internal device. updateDeviceInfo(nodepath, new_major, new_minor); /* Get the device nodes again, because they just changed */ n = getDeviceNodes((dev_t *) &deviceNodes, DirectVolume::MAX_PARTITIONS); if (!n) { SLOGE("Failed to get device nodes (%s)\n", strerror(errno)); return -1; } } } #ifdef MTK_MULTI_PARTITION_MOUNT_ONLY_SUPPORT if (0 == strcmp(getLabel(), "usbotg")) { setState(Volume::State_Checking); if (0 != mkdir(getMountpoint(), 0700)) { SLOGE("usbotg: Volume mountVol (%s) mkdir failed (%s)" , getMountpoint(), strerror(errno)); } else { SLOGD("usbotg: Volume mountVol (%s) mkdir success", getMountpoint()); } if (0 != chown(getMountpoint(), AID_MEDIA_RW, AID_MEDIA_RW)) { SLOGE("usbotg: Volume mountVol (%s) mkdir failed (%s)" , getMountpoint(), strerror(errno)); } else { SLOGD("usbotg: Volume mountVol (%s) mkdir success", getMountpoint()); } if (0 != mkdir(getFuseMountpoint(), 0755)) { SLOGE("usbotg: Volume mountVol (%s) mkdir failed (%s)" , getFuseMountpoint(), strerror(errno)); } else { SLOGD("usbotg: Volume mountVol (%s) mkdir success", getFuseMountpoint()); } int fd; int counter = 0; while(1) { counter++; if( counter == 10) { SLOGD("timeout open otgNodePath counter:%d\n",counter); break; } if ((fd = open(otgNodePath, O_RDONLY)) < 0) { SLOGE(" cannot open device '%s' (errno=%d) (%s)", otgNodePath, errno,strerror(errno)); usleep(30000); } else { SLOGD(" can access %s successfully", otgNodePath); close(fd); break; } } if (Fat::check(otgNodePath)) { SLOGE("usbotg: %s fat check fail (%s)\n", otgNodePath, strerror(errno)); char cmd[255] = {0}; sprintf(cmd, "/system/bin/sh -c \"rm -r %s\"", getFuseMountpoint()); system(cmd); SLOGD("usbotg: Volume unmountVol cmd = %s !!!", cmd); sprintf(cmd, "/system/bin/sh -c \"rm -r %s\"", getMountpoint()); system(cmd); SLOGD("usbotg: Volume unmountVol cmd = %s !!!", cmd); return -1; } if (Fat::doMount(otgNodePath, getMountpoint(), false, false, false, AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) { SLOGE("usbotg: Volume mountVol %s Otg failed to mount via VFAT (%s)\n", otgNodePath, strerror(errno)); char cmd[255] = {0}; sprintf(cmd, "/system/bin/sh -c \"rm -r %s\"", getFuseMountpoint()); system(cmd); SLOGD("usbotg: Volume unmountVol cmd = %s !!!", cmd); sprintf(cmd, "/system/bin/sh -c \"rm -r %s\"", getMountpoint()); system(cmd); SLOGD("usbotg: Volume unmountVol cmd = %s !!!", cmd); setState(Volume::State_Idle); return -1; } extractMetadata(otgNodePath); //fork sdcard process instead of witch service in init.rc struct sigaction act, oact; act.sa_handler = sigCld; act.sa_flags = 0; sigemptyset(&act.sa_mask); if (sigaction(SIGCHLD, &act, &oact) <0) { SLOGD("Error occured on signal"); return -1; } pid_t pid = fork(); if (pid < 0) { SLOGD("Error occured on fork"); return 0; } else if (pid == 0) { SLOGD("usbotg: Volume mountVol go execv,pid=%d", pid); const char* mountCmd = "/system/bin/sdcard"; const char* mountpoint = getMountpoint(); const char* fusemountpoint = getFuseMountpoint(); const char* argv0[] = { mountCmd, "-u", "1023", "-g", "1023", "-w", "1023", "-d", mountpoint, fusemountpoint, NULL }; SLOGD("%s %s %s %s %s %s %s %s %s %s", argv0[0], argv0[1], argv0[2], argv0[3], argv0[4], argv0[5], argv0[6], argv0[7], argv0[8], argv0[9]); if (execv(mountCmd,(char* const*)argv0) < 0) { ALOGE("execv(%s) failed: %s\n", mountCmd, strerror(errno)); SLOGD("usbotg: Volume mountVol mounted failed"); char cmd[255] = {0}; sprintf(cmd, "/system/bin/sh -c \"rm -r %s\"", getFuseMountpoint()); system(cmd); SLOGD("usbotg: Volume unmountVol cmd = %s !!!", cmd); sprintf(cmd, "/system/bin/sh -c \"rm -r %s\"", getMountpoint()); system(cmd); SLOGD("usbotg: Volume unmountVol cmd = %s !!!", cmd); exit(127); } exit(127); } else{ SLOGD("usbotg: Volume mountVol mounted succed,pid=%d",pid); setState(Volume::State_Mounted); mPid = pid; return 0; } } #endif for (i = 0; i < n; i++) { char devicePath[255]; sprintf(devicePath, "/dev/block/vold/%d:%d", major(deviceNodes[i]), minor(deviceNodes[i])); if (deviceNodes[i] == (dev_t)(-1)) { SLOGE("Partition '%s' is invalid dev_t. Skip mounting!", devicePath); continue; } SLOGI("%s being considered for volume %s\n", devicePath, getLabel()); errno = 0; if ((getState() == Volume::State_NoMedia) ) { SLOGI("NoMedia! skip mounting the storage. Update errno to ENODEV"); errno = ENODEV; return -1; } setState(Volume::State_Checking); /* * If FS check failed, we should move on to next partition * instead of returning an error */ __CHECK_FAT_AGAIN: if (Fat::check(devicePath)) { #if 0 if (errno == ENODATA) { SLOGW("%s does not contain a FAT filesystem\n", devicePath); continue; } errno = EIO; /* Badness - abort the mount */ SLOGE("%s failed FS checks (%s)", devicePath, strerror(errno)); setState(Volume::State_Idle); return -1; #else #ifdef MTK_EMMC_SUPPORT if ( mVm->isFirstBoot() && IsEmmcStorage()) { SLOGI("** This is first boot and internal sd is not formatted. Try to format it. (%s)\n", devicePath); if (Fat::format(devicePath, 0, false)) { SLOGE("Failed to format (%s)", strerror(errno)); } else { SLOGI("Format successfully. (%s)\n", devicePath); property_set("persist.vold.first_boot", "0"); goto __CHECK_FAT_AGAIN; } } #endif #ifdef MTK_FAT_ON_NAND char first_boot[PROPERTY_VALUE_MAX] ; property_get("persist.vold.fat_first_boot", first_boot, "1"); if (!strcmp(first_boot, "1") && !strcmp(getLabel(), "sdcard0")) { SLOGI("** This is first boot and internal sd is not formatted. Try to format it. (%s)\n", devicePath); if (Fat::format(devicePath, 0, false)) { SLOGE("Failed to format %s(%d)", strerror(errno), errno); } else { SLOGI("%s format successfully\n", devicePath); property_set("persist.vold.fat_first_boot", "0"); goto __CHECK_FAT_AGAIN; } } #endif SLOGW("%s failed FS checks, move on to next partition", devicePath); continue; #endif } #ifdef MTK_EMMC_SUPPORT else { if ( mVm->isFirstBoot() && IsEmmcStorage()) { property_set("persist.vold.first_boot", "0"); } } #endif errno = 0; int gid; #ifdef MTK_EMMC_DISCARD if (Fat::doMount(devicePath, getMountpoint(), false, false, false, AID_MEDIA_RW, AID_MEDIA_RW, 0007, true, IsEmmcStorage())) { SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno)); continue; } #else //MTK_EMMC_DISCARD if (Fat::doMount(devicePath, getMountpoint(), false, false, false, AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) { SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno)); continue; } #endif //MTK_EMMC_DISCARD SLOGI("providesAsec = %d", providesAsec); extractMetadata(devicePath); #ifdef MTK_2SDCARD_SWAP char secImgDir[PATH_MAX]; sprintf(secImgDir, "%s/.android_secure", getMountpoint()); SLOGI("Create %s in advance", secImgDir); /* Whether primary or secondary storage, create .android folder in advance to prevent from media out of space for Bindmounts fail This case happens in SWAP feature. */ if (access(secImgDir, R_OK | X_OK)) { if (errno == ENOENT) { if (mkdir(secImgDir, 0777)) { SLOGE("Failed to create %s (%s)", secImgDir, strerror(errno)); } } else { SLOGE("Failed to access %s (%s)", secImgDir, strerror(errno)); } } #endif if (providesAsec && mountAsecExternal() != 0) { SLOGE("Failed to mount secure area (%s)", strerror(errno)); umount(getMountpoint()); setState(Volume::State_Idle); return -1; } char service[64]; char service_id[64]; strcpy(service_id, getMountpoint()+strlen(Volume::MEDIA_DIR)+1); snprintf(service, 64, "fuse_%s", service_id); property_set("ctl.start", service); waitForServiceState(service, "running"); int fd; if ((fd = open(devicePath, O_RDONLY)) < 0) { SLOGE("Cannot open device '%s' (errno=%d)", devicePath, errno); } else { setState(Volume::State_Mounted, Fat::isFat32(fd)); close(fd); } mCurrentlyMountedKdev = deviceNodes[i]; return 0; } SLOGE("Volume %s found no suitable devices for mounting :(\n", getLabel()); curState = getState(); if (curState == Volume::State_NoMedia) { SLOGI("Mount fail caused by NoMedia! Update errno to ENODEV"); errno = ENODEV; } if ((curState != Volume::State_NoMedia) && (curState != Volume::State_Mounted)) { setState(Volume::State_Idle); } if(curState == Volume::State_Mounted) { return 0; } return -1; }
int Volume::unmountVol(bool force, bool revert) { int i, rc; int flags = getFlags(); bool providesAsec = (flags & VOL_PROVIDES_ASEC) != 0; bool is_emulated_sd = false; #ifdef MTK_SHARED_SDCARD if (IsEmmcStorage()) { providesAsec = false; is_emulated_sd = true; } #endif if (getState() != Volume::State_Mounted) { SLOGE("Volume %s unmount request when not mounted", getLabel()); errno = EINVAL; return UNMOUNT_NOT_MOUNTED_ERR; } #ifdef MTK_MULTI_PARTITION_MOUNT_ONLY_SUPPORT if (false == isMountpointMounted(getFuseMountpoint())) { SLOGD("usbotg: Volume unmountVol %s is already unmounted", getFuseMountpoint()); goto unmount_success; } #endif setState(Volume::State_Unmounting); usleep(1000 * 100); // Give the framework some time to react char service[64]; char service_id[64]; strcpy(service_id, getMountpoint()+strlen(Volume::MEDIA_DIR)+1); snprintf(service, 64, "fuse_%s", service_id); if (is_emulated_sd) { snprintf(service, 64, "sdcard"); } #ifdef MTK_MULTI_PARTITION_MOUNT_ONLY_SUPPORT if (0 == strcmp(getLabel(), "usbotg")) { sPid = mPid; SLOGD("usbotg: Volume unmountVol ,mPid=%d",mPid); if(-1 != mPid) { kill(mPid,SIGKILL); } SLOGD("usbotg: Volume unmountVol ,mountpoint=%s",getFuseMountpoint()); if (doUnmount(getFuseMountpoint(), force)) { SLOGE("Failed to unmount %s (%s)", getFuseMountpoint(), strerror(errno)); goto fail_remount_secure; } if (doUnmount(getMountpoint(), force)) { SLOGE("Failed to unmount %s (%s)", getMountpoint(), strerror(errno)); goto fail_remount_secure; } SLOGI("usbotg: Volume unmounted sucessfully"); } else { property_set("ctl.stop", service); /* Give it a chance to stop. I wish we had a synchronous way to determine this... */ //sleep(1); waitForServiceState(service, "stopped"); // TODO: determine failure mode if FUSE times out if (providesAsec && doUnmount(Volume::SEC_ASECDIR_EXT, force) != 0) { SLOGE("Failed to unmount secure area on %s (%s)", getMountpoint(), strerror(errno)); goto out_mounted; } /* Now that the fuse daemon is dead, unmount it */ if (doUnmount(getFuseMountpoint(), force) != 0) { SLOGE("Failed to unmount %s (%s)", getFuseMountpoint(), strerror(errno)); goto fail_remount_secure; } /* Unmount the real sd card */ if (!is_emulated_sd) { if (doUnmount(getMountpoint(), force) != 0) { SLOGE("Failed to unmount %s (%s)", getMountpoint(), strerror(errno)); goto fail_remount_secure; } SLOGI("%s unmounted successfully", getMountpoint()); } } #else { #define MAX_NEED_TO_WAIT 10 bool need_to_wait = false; int need_to_wait_count = 0; do { Process::killProcessesWithOpenFiles(getFuseMountpoint(), 0, "mdlogger", &need_to_wait); if(need_to_wait) { need_to_wait_count++; SLOGI("need_to_wait=%d, need_to_wait_count=%d,", need_to_wait, need_to_wait_count); usleep(1000*1000); } else { break; } } while (need_to_wait && need_to_wait_count < MAX_NEED_TO_WAIT); property_set("ctl.stop", service); /* Give it a chance to stop. I wish we had a synchronous way to determine this... */ //sleep(1); waitForServiceState(service, "stopped"); // TODO: determine failure mode if FUSE times out if (providesAsec && doUnmount(Volume::SEC_ASECDIR_EXT, force) != 0) { SLOGE("Failed to unmount secure area on %s (%s)", getMountpoint(), strerror(errno)); goto out_mounted; } /* Now that the fuse daemon is dead, unmount it */ if (doUnmount(getFuseMountpoint(), force) != 0) { SLOGE("Failed to unmount %s (%s)", getFuseMountpoint(), strerror(errno)); goto fail_remount_secure; } /* Unmount the real sd card */ if (!is_emulated_sd) { if (doUnmount(getMountpoint(), force) != 0) { SLOGE("Failed to unmount %s (%s)", getMountpoint(), strerror(errno)); goto fail_remount_secure; } SLOGI("%s unmounted successfully", getMountpoint()); } } #endif /* If this is an encrypted volume, and we've been asked to undo * the crypto mapping, then revert the dm-crypt mapping, and revert * the device info to the original values. */ if (revert && isDecrypted()) { cryptfs_revert_volume(getLabel()); revertDeviceInfo(); SLOGI("Encrypted volume %s reverted successfully", getMountpoint()); } setUuid(NULL); setUserLabel(NULL); setState(Volume::State_Idle); unmount_success: mCurrentlyMountedKdev = -1; #ifdef MTK_MULTI_PARTITION_MOUNT_ONLY_SUPPORT if (0 == strcmp(getLabel(), "usbotg")) { char cmd[255] = {0}; sprintf(cmd, "/system/bin/sh -c \"rm -r %s\"", getFuseMountpoint()); system(cmd); SLOGD("usbotg: Volume unmountVol cmd = %s !!!", cmd); sprintf(cmd, "/system/bin/sh -c \"rm -r %s\"", getMountpoint()); system(cmd); SLOGD("usbotg: Volume unmountVol cmd = %s !!!", cmd); //remove(getMountpoint()); } #endif return 0; fail_remount_secure: if (providesAsec && mountAsecExternal() != 0) { SLOGE("Failed to remount secure area (%s)", strerror(errno)); goto out_nomedia; } out_mounted: property_set("ctl.start", service); waitForServiceState(service, "running"); setState(Volume::State_Mounted); return -1; out_nomedia: setState(Volume::State_NoMedia); return -1; }
int Volume::mountVol() { dev_t deviceNodes[4]; int n, i, rc = 0; char errmsg[255]; const char* externalStorage = getenv("EXTERNAL_STORAGE"); bool primaryStorage = externalStorage && !strcmp(getMountpoint(), externalStorage); char decrypt_state[PROPERTY_VALUE_MAX]; char crypto_state[PROPERTY_VALUE_MAX]; char encrypt_progress[PROPERTY_VALUE_MAX]; int flags; property_get("vold.decrypt", decrypt_state, ""); property_get("vold.encrypt_progress", encrypt_progress, ""); /* Don't try to mount the volumes if we have not yet entered the disk password * or are in the process of encrypting. */ if ((getState() == Volume::State_NoMedia) || ((!strcmp(decrypt_state, "1") || encrypt_progress[0]) && primaryStorage)) { snprintf(errmsg, sizeof(errmsg), "Volume %s %s mount failed - no media", getLabel(), getMountpoint()); mVm->getBroadcaster()->sendBroadcast( ResponseCode::VolumeMountFailedNoMedia, errmsg, false); errno = ENODEV; return -1; } else if (getState() != Volume::State_Idle) { errno = EBUSY; if (getState() == Volume::State_Pending) { mRetryMount = true; } return -1; } if (isMountpointMounted(getMountpoint())) { SLOGW("Volume is idle but appears to be mounted - fixing"); setState(Volume::State_Mounted); // mCurrentlyMountedKdev = XXX return 0; } n = getDeviceNodes((dev_t *) &deviceNodes, 4); if (!n) { SLOGE("Failed to get device nodes (%s)\n", strerror(errno)); return -1; } /* If we're running encrypted, and the volume is marked as encryptable and nonremovable, * and vold is asking to mount the primaryStorage device, then we need to decrypt * that partition, and update the volume object to point to it's new decrypted * block device */ property_get("ro.crypto.state", crypto_state, ""); flags = getFlags(); if (primaryStorage && ((flags & (VOL_NONREMOVABLE | VOL_ENCRYPTABLE))==(VOL_NONREMOVABLE | VOL_ENCRYPTABLE)) && !strcmp(crypto_state, "encrypted") && !isDecrypted()) { char new_sys_path[MAXPATHLEN]; char nodepath[256]; int new_major, new_minor; if (n != 1) { /* We only expect one device node returned when mounting encryptable volumes */ SLOGE("Too many device nodes returned when mounting %d\n", getMountpoint()); return -1; } if (cryptfs_setup_volume(getLabel(), MAJOR(deviceNodes[0]), MINOR(deviceNodes[0]), new_sys_path, sizeof(new_sys_path), &new_major, &new_minor)) { SLOGE("Cannot setup encryption mapping for %d\n", getMountpoint()); return -1; } /* We now have the new sysfs path for the decrypted block device, and the * majore and minor numbers for it. So, create the device, update the * path to the new sysfs path, and continue. */ snprintf(nodepath, sizeof(nodepath), "/dev/block/vold/%d:%d", new_major, new_minor); if (createDeviceNode(nodepath, new_major, new_minor)) { SLOGE("Error making device node '%s' (%s)", nodepath, strerror(errno)); } // Todo: Either create sys filename from nodepath, or pass in bogus path so // vold ignores state changes on this internal device. updateDeviceInfo(nodepath, new_major, new_minor); /* Get the device nodes again, because they just changed */ n = getDeviceNodes((dev_t *) &deviceNodes, 4); if (!n) { SLOGE("Failed to get device nodes (%s)\n", strerror(errno)); return -1; } } for (i = 0; i < n; i++) { char devicePath[255]; sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(deviceNodes[i]), MINOR(deviceNodes[i])); SLOGI("%s being considered for volume %s\n", devicePath, getLabel()); errno = 0; setState(Volume::State_Checking); if (Fat::check(devicePath)) { if (errno == ENODATA) { SLOGW("%s does not contain a FAT filesystem\n", devicePath); continue; } errno = EIO; /* Badness - abort the mount */ SLOGE("%s failed FS checks (%s)", devicePath, strerror(errno)); setState(Volume::State_Idle); return -1; } /* * Mount the device on our internal staging mountpoint so we can * muck with it before exposing it to non priviledged users. */ errno = 0; int gid; if (primaryStorage) { // Special case the primary SD card. // For this we grant write access to the SDCARD_RW group. gid = AID_SDCARD_RW; } else { // For secondary external storage we keep things locked up. gid = AID_MEDIA_RW; } if (Fat::doMount(devicePath, "/mnt/secure/staging", false, false, false, AID_SYSTEM, gid, 0702, true)) { SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno)); continue; } SLOGI("Device %s, target %s mounted @ /mnt/secure/staging", devicePath, getMountpoint()); protectFromAutorunStupidity(); // only create android_secure on primary storage if (primaryStorage && createBindMounts()) { SLOGE("Failed to create bindmounts (%s)", strerror(errno)); umount("/mnt/secure/staging"); setState(Volume::State_Idle); return -1; } /* * Now that the bindmount trickery is done, atomically move the * whole subtree to expose it to non priviledged users. */ if (doMoveMount("/mnt/secure/staging", getMountpoint(), false)) { SLOGE("Failed to move mount (%s)", strerror(errno)); umount("/mnt/secure/staging"); setState(Volume::State_Idle); return -1; } setState(Volume::State_Mounted); mCurrentlyMountedKdev = deviceNodes[i]; return 0; } SLOGE("Volume %s found no suitable devices for mounting :(\n", getLabel()); setState(Volume::State_Idle); return -1; }
int Volume::formatVol() { dev_t deviceNodes[MAX_SUP_PART]; int part_num; if (getState() == Volume::State_NoMedia) { errno = ENODEV; return -1; } else if (getState() != Volume::State_Idle) { errno = EBUSY; return -1; } if (isMountpointMounted(getMountpoint())) { SLOGW("Volume is idle but appears to be mounted - fixing"); setState(Volume::State_Mounted); // mCurrentlyMountedKdev = XXX errno = EBUSY; return -1; } bool formatEntireDevice = ((mPartIdx == -1) && (0 != getDeviceNumParts())); char devicePath[255]; dev_t diskNode = getDiskDevice(); //dev_t partNode = MKDEV(MAJOR(diskNode), (formatEntireDevice ? 1 : mPartIdx)); //part_num reserved for mutiple partition support // getDeviceNodes((dev_t *) &deviceNodes, MAX_SUP_PART); part_num = 1; dev_t partNode = deviceNodes[part_num - 1]; setState(Volume::State_Formatting); int ret = -1; // Only initialize the MBR if we are formatting the entire device if (formatEntireDevice) { sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(diskNode), MINOR(diskNode)); SLOGI("mDiskNumParts = %d\n", getDeviceNumParts()); if (initializeMbr(devicePath)) { SLOGE("Failed to initialize MBR (%s)", strerror(errno)); goto err; } } sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(partNode), MINOR(partNode)); SLOGI("mDiskNumParts = %d\n", getDeviceNumParts()); if (mDebug) { SLOGI("Formatting volume %s (%s)", getLabel(), devicePath); } if (Fat::format(devicePath, 0)) { SLOGE("Failed to format (%s)", strerror(errno)); goto err; } ret = 0; err: setState(Volume::State_Idle); return ret; }