void DirectVolume::handleDiskRemoved(const char *devpath, NetlinkEvent *evt) { int major = atoi(evt->findParam("MAJOR")); int minor = atoi(evt->findParam("MINOR")); char msg[255]; int state; if(0 == mDiskNumParts) { state = getState(); if (state != Volume::State_Mounted && state != Volume::State_Shared) { SLOGD("Status is %d, skip unmountVol()", getState()); } else if ((dev_t) MKDEV(major, minor) == mCurrentlyMountedKdev) { /* * Yikes, our mounted partition is going away! */ snprintf(msg, sizeof(msg), "Volume %s %s bad removal (%d:%d)", getLabel(), getMountpoint(), major, minor); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeBadRemoval, msg, false); mVm->waitForAfCleanupAsec(this); if (Volume::unmountVol(true, false)) { SLOGE("Failed to unmount volume on bad removal (%s)", strerror(errno)); // XXX: At this point we're screwed for now } else { SLOGD("Crisis averted"); } } else if (state == Volume::State_Shared) { /* removed during mass storage */ snprintf(msg, sizeof(msg), "Volume %s bad removal (%d:%d)", getLabel(), major, minor); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeBadRemoval, msg, false); if (mVm->unshareVolume(getLabel(), "ums")) { SLOGE("Failed to unshare volume on bad removal (%s)", strerror(errno)); } else { SLOGD("Crisis averted"); } } } SLOGD("Volume %s %s disk %d:%d removed\n", getLabel(), getMountpoint(), major, minor); if(mVm->getIpoState() == VolumeManager::State_Ipo_Start) { snprintf(msg, sizeof(msg), "Volume %s %s disk removed (%d:%d)", getLabel(), getMountpoint(), major, minor); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskRemoved, msg, false); } setState(Volume::State_NoMedia); }
void DirectVolume::handleDiskRemoved(const char *devpath, NetlinkEvent *evt) { int major = atoi(evt->findParam("MAJOR")); int minor = atoi(evt->findParam("MINOR")); char msg[255]; SLOGD("Volume %s %s disk %d:%d removed\n", getLabel(), getMountpoint(), major, minor); snprintf(msg, sizeof(msg), "Volume %s %s disk removed (%d:%d)", getLabel(), getMountpoint(), major, minor); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskRemoved, msg, false); setState(Volume::State_NoMedia); }
void DirectVolume::handlePartitionRemoved(const char *devpath, NetlinkEvent *evt) { int major = atoi(evt->findParam("MAJOR")); int minor = atoi(evt->findParam("MINOR")); char msg[255]; int state; SLOGD("Volume %s %s partition %d:%d removed\n", getLabel(), getMountpoint(), major, minor); /* * The framework doesn't need to get notified of * partition removal unless it's mounted. Otherwise * the removal notification will be sent on the Disk * itself */ state = getState(); if (state != Volume::State_Mounted && state != Volume::State_Shared) { return; } if ((dev_t) MKDEV(major, minor) == mCurrentlyMountedKdev) { /* * Yikes, our mounted partition is going away! */ snprintf(msg, sizeof(msg), "Volume %s %s bad removal (%d:%d)", getLabel(), getMountpoint(), major, minor); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeBadRemoval, msg, false); mVm->waitForAfCleanupAsec(this); if (Volume::unmountVol(true, false)) { SLOGE("Failed to unmount volume on bad removal (%s)", strerror(errno)); // XXX: At this point we're screwed for now } else { SLOGD("Crisis averted"); } } else if (state == Volume::State_Shared) { /* removed during mass storage */ snprintf(msg, sizeof(msg), "Volume %s bad removal (%d:%d)", getLabel(), major, minor); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeBadRemoval, msg, false); if (mVm->unshareVolume(getLabel(), "ums")) { SLOGE("Failed to unshare volume on bad removal (%s)", strerror(errno)); } else { SLOGD("Crisis averted"); } } }
void Volume::setState(int state) { char msg[255]; int oldState = mState; if (oldState == state) { SLOGW("Duplicate state (%d)\n", state); return; } if ((oldState == Volume::State_Pending) && (state != Volume::State_Idle)) { mRetryMount = false; } mState = state; SLOGD("Volume %s state changing %d (%s) -> %d (%s)", mLabel, oldState, stateToStr(oldState), mState, stateToStr(mState)); snprintf(msg, sizeof(msg), "Volume %s %s state changed from %d (%s) to %d (%s)", getLabel(), getMountpoint(), oldState, stateToStr(oldState), mState, stateToStr(mState)); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeStateChange, msg, false); }
int DirectVolume::handleBlockEvent(NetlinkEvent *evt) { const char *dp = evt->findParam("DEVPATH"); PathCollection::iterator it; for (it = mPaths->begin(); it != mPaths->end(); ++it) { if (!strncmp(dp, *it, strlen(*it))) { /* We can handle this disk */ int action = evt->getAction(); const char *devtype = evt->findParam("DEVTYPE"); if (action == NetlinkEvent::NlActionAdd) { int major = atoi(evt->findParam("MAJOR")); int minor = atoi(evt->findParam("MINOR")); char nodepath[255]; snprintf(nodepath, sizeof(nodepath), "/dev/block/vold/%d:%d", major, minor); if (createDeviceNode(nodepath, major, minor)) { SLOGE("Error making device node '%s' (%s)", nodepath, strerror(errno)); } if (!strcmp(devtype, "disk")) { handleDiskAdded(dp, evt); } else { handlePartitionAdded(dp, evt); } /* Send notification iff disk is ready (ie all partitions found) */ if (getState() == Volume::State_Idle) { char msg[255]; snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)", getLabel(), getMountpoint(), mDiskMajor, mDiskMinor); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted, msg, false); } } else if (action == NetlinkEvent::NlActionRemove) { if (!strcmp(devtype, "disk")) { handleDiskRemoved(dp, evt); } else { handlePartitionRemoved(dp, evt); } } else if (action == NetlinkEvent::NlActionChange) { if (!strcmp(devtype, "disk")) { handleDiskChanged(dp, evt); } else { handlePartitionChanged(dp, evt); } } else { SLOGW("Ignoring non add/remove/change event"); } return 0; } } errno = ENODEV; 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; } 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; }
void DirectVolume::handleDiskRemoved(const char *devpath, NetlinkEvent *evt) { int major = atoi(evt->findParam("MAJOR")); int minor = atoi(evt->findParam("MINOR")); char msg[255]; bool enabled; if(first_udisk_major!=-1&&first_udisk_minor!=-1){ if(first_udisk_major == major && first_udisk_minor == minor){ SLOGD("first udisk remove\n"); first_udisk_major = -1; first_udisk_minor = -1; }else{ SLOGD("not the first udisk remove,do nothing\n"); return; } } if (mVm->shareEnabled(getLabel(), "ums", &enabled) == 0 && enabled) { mVm->unshareVolume(getLabel(), "ums"); } SLOGD("Volume %s %s disk %d:%d removed\n", getLabel(), getMountpoint(), major, minor); snprintf(msg, sizeof(msg), "Volume %s %s disk removed (%d:%d)", getLabel(), getMountpoint(), major, minor); if(!mDiskNumParts){ if (Volume::unmountVol(true, false)) { SLOGE("Failed to unmount volume on bad removal (%s)", strerror(errno)); } else { SLOGD("Crisis averted"); } } mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskRemoved, msg, false); setState(Volume::State_NoMedia); }
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; }
void DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt) { mDiskMajor = atoi(evt->findParam("MAJOR")); mDiskMinor = atoi(evt->findParam("MINOR")); const char *tmp = evt->findParam("NPARTS"); if (tmp) { mDiskNumParts = atoi(tmp); } else { SLOGW("Kernel block uevent missing 'NPARTS'"); mDiskNumParts = 1; } if (strcmp(devpath, "/devices/virtual/block/stheno") == 0) mDiskNumParts = 0; char msg[255]; int partmask = 0; int i; for (i = 1; i <= mDiskNumParts; i++) { partmask |= (1 << i); } mPendingPartMap = partmask; if (mDiskNumParts == 0) { #ifdef PARTITION_DEBUG SLOGD("Dv::diskIns - No partitions - good to go son!"); #endif setState(Volume::State_Idle); } else { #ifdef PARTITION_DEBUG SLOGD("Dv::diskIns - waiting for %d partitions (mask 0x%x)", mDiskNumParts, mPendingPartMap); #endif setState(Volume::State_Pending); } snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)", getLabel(), getMountpoint(), mDiskMajor, mDiskMinor); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted, msg, false); }
void DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt) { mDiskMajor = atoi(evt->findParam("MAJOR")); mDiskMinor = atoi(evt->findParam("MINOR")); const char *tmp = evt->findParam("NPARTS"); if (tmp) { mDiskNumParts = atoi(tmp); } else { SLOGW("Kernel block uevent missing 'NPARTS'"); mDiskNumParts = 1; } char msg[255]; /* int partmask = 0; int i; for (i = 1; i <= mDiskNumParts; i++) { partmask |= (1 << i); } */ mPendingPartNum = mDiskNumParts; for (int i = 0; i < MAX_PARTITIONS; i++) mPartMinors[i] = -1; if (mDiskNumParts == 0) { #ifdef PARTITION_DEBUG SLOGD("Dv::diskIns - No partitions - good to go son!"); #endif setState(Volume::State_Idle); } else { #ifdef PARTITION_DEBUG SLOGD("Dv::diskIns - waiting for %d partitions (pending partitions: %d)", mDiskNumParts, mPendingPartNum); #endif setState(Volume::State_Pending); } if(mVm->getIpoState() == VolumeManager::State_Ipo_Start) { snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)", getLabel(), getMountpoint(), mDiskMajor, mDiskMinor); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted, msg, false); } }
int Volume::unmountVol(bool force, bool revert) { int i, rc; if (getState() != Volume::State_Mounted) { SLOGE("Volume %s unmount request when not mounted", getLabel()); errno = EINVAL; return UNMOUNT_NOT_MOUNTED_ERR; } setState(Volume::State_Unmounting); usleep(1000 * 1000); // Give the framework some time to react /* * First move the mountpoint back to our internal staging point * so nobody else can muck with it while we work. */ if (doMoveMount(getMountpoint(), SEC_STGDIR, force)) { SLOGE("Failed to move mount %s => %s (%s)", getMountpoint(), SEC_STGDIR, strerror(errno)); setState(Volume::State_Mounted); return -1; } protectFromAutorunStupidity(); /* * Unmount the tmpfs which was obscuring the asec image directory * from non root users */ if (doUnmount(Volume::SEC_STG_SECIMGDIR, force)) { SLOGE("Failed to unmount tmpfs on %s (%s)", SEC_STG_SECIMGDIR, strerror(errno)); goto fail_republish; } /* * Remove the bindmount we were using to keep a reference to * the previously obscured directory. */ if (doUnmount(Volume::SEC_ASECDIR, force)) { SLOGE("Failed to remove bindmount on %s (%s)", SEC_ASECDIR, strerror(errno)); goto fail_remount_tmpfs; } /* * Finally, unmount the actual block device from the staging dir */ if (doUnmount(Volume::SEC_STGDIR, force)) { SLOGE("Failed to unmount %s (%s)", SEC_STGDIR, strerror(errno)); goto fail_recreate_bindmount; } SLOGI("%s unmounted sucessfully", getMountpoint()); /* 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()); } setState(Volume::State_Idle); mCurrentlyMountedKdev = -1; return 0; /* * Failure handling - try to restore everything back the way it was */ fail_recreate_bindmount: if (mount(SEC_STG_SECIMGDIR, SEC_ASECDIR, "", MS_BIND, NULL)) { SLOGE("Failed to restore bindmount after failure! - Storage will appear offline!"); goto out_nomedia; } fail_remount_tmpfs: if (mount("tmpfs", SEC_STG_SECIMGDIR, "tmpfs", MS_RDONLY, "size=0,mode=0,uid=0,gid=0")) { SLOGE("Failed to restore tmpfs after failure! - Storage will appear offline!"); goto out_nomedia; } fail_republish: if (doMoveMount(SEC_STGDIR, getMountpoint(), force)) { SLOGE("Failed to republish mount after failure! - Storage will appear offline!"); goto out_nomedia; } 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() { 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; }
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 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; }
void DirectVolume::handlePartitionRemoved(const char *devpath, NetlinkEvent *evt) { int major = atoi(evt->findParam("MAJOR")); int minor = atoi(evt->findParam("MINOR")); char msg[255]; int state; SLOGD("Volume %s %s partition %d:%d removed\n", getLabel(), getMountpoint(), major, minor); char voldpath[255]; sprintf(voldpath,"/dev/block/vold/%d:%d",major,minor); sem_wait(udisk_sem); for(int i=0;i<EXTRA_UDISK_NUM;i++){ //SLOGD("extra_udisk_valid[%d] %d %s\n",i,extra_udisk_valid[i],extra_udisk_devpath[i]); if(extra_udisk_valid[i]!=0&&!strcmp(voldpath,extra_udisk_devpath[i])){ SLOGD("doUnmount extra_udisk_path %s\n",extra_udisk_mountpath[i]); if (doUnmount(extra_udisk_mountpath[i], true)) { SLOGE("Failed to remove bindmount on %s (%s)", SEC_ASECDIR_EXT, strerror(errno)); sem_post(udisk_sem); return; } extra_udisk_valid[i] = 0; udiskSetState(State_Unmounting,i,extra_udisk_mountpath[i]); udiskSetState(State_Idle,i,extra_udisk_mountpath[i]); udiskSetState(State_NoMedia,i,extra_udisk_mountpath[i]); snprintf(msg, sizeof(msg), "Volume Udisk%d %s disk removed (%d:%d)", i, extra_udisk_mountpath[i], major, minor); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskRemoved, msg, false); sem_post(udisk_sem); return; } } sem_post(udisk_sem); /* * The framework doesn't need to get notified of * partition removal unless it's mounted. Otherwise * the removal notification will be sent on the Disk * itself */ state = getState(); /* Remove event interrupted the add event, if state is checking, * let remove event sleep, add event complete than remove event. */ while (state == Volume::State_Checking) { sleep(1); SLOGD("code from tp,Fail removed state =%d", state); state = getState(); SLOGD("code from tp,new removed state =%d", state); } if (state != Volume::State_Mounted && state != Volume::State_Shared) { return; } if ((dev_t) MKDEV(major, minor) == mCurrentlyMountedKdev) { /* * Yikes, our mounted partition is going away! */ snprintf(msg, sizeof(msg), "Volume %s %s bad removal (%d:%d)", getLabel(), getMountpoint(), major, minor); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeBadRemoval, msg, false); if (mVm->cleanupAsec(this, true)) { SLOGE("Failed to cleanup ASEC - unmount will probably fail!"); } if (Volume::unmountVol(true, false)) { SLOGE("Failed to unmount volume on bad removal (%s)", strerror(errno)); // XXX: At this point we're screwed for now } else { SLOGD("Crisis averted"); } } else if (state == Volume::State_Shared) { /* removed during mass storage */ snprintf(msg, sizeof(msg), "Volume %s bad removal (%d:%d)", getLabel(), major, minor); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeBadRemoval, msg, false); if (mVm->unshareVolume(getLabel(), "ums")) { SLOGE("Failed to unshare volume on bad removal (%s)", strerror(errno)); } else { SLOGD("Crisis averted"); } } }
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::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; }
bool Volume::isPrimaryStorage() { const char* externalStorage = getenv("EXTERNAL_STORAGE") ? : "/mnt/sdcard"; return !strcmp(getMountpoint(), externalStorage); }
void DirectVolume::handlePartitionChanged(const char *devpath, NetlinkEvent *evt) { int major = atoi(evt->findParam("MAJOR")); int minor = atoi(evt->findParam("MINOR")); SLOGD("Volume %s %s partition %d:%d changed\n", getLabel(), getMountpoint(), major, minor); }
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; }
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::unmountVol(bool force) { int i, rc; if (getState() != Volume::State_Mounted) { SLOGE("Volume %s unmount request when not mounted", getLabel()); errno = EINVAL; return -1; } setState(Volume::State_Unmounting); usleep(1000 * 1000); // Give the framework some time to react /* * First move the mountpoint back to our internal staging point * so nobody else can muck with it while we work. */ if (doMoveMount(getMountpoint(), SEC_STGDIR, force)) { SLOGE("Failed to move mount %s => %s (%s)", getMountpoint(), SEC_STGDIR, strerror(errno)); setState(Volume::State_Mounted); return -1; } protectFromAutorunStupidity(); /* Undo createBindMounts(), which is only called for EXTERNAL_STORAGE */ const char *externalPath = getenv("EXTERNAL_STORAGE") ?: "/mnt/sdcard"; if (0 == strcmp(getMountpoint(), externalPath)) { /* * Unmount the tmpfs which was obscuring the asec image directory * from non root users */ if (doUnmount(Volume::SEC_STG_SECIMGDIR, force)) { SLOGE("Failed to unmount tmpfs on %s (%s)", SEC_STG_SECIMGDIR, strerror(errno)); goto fail_republish; } /* * Remove the bindmount we were using to keep a reference to * the previously obscured directory. */ if (doUnmount(Volume::SEC_ASECDIR, force)) { SLOGE("Failed to remove bindmount on %s (%s)", SEC_ASECDIR, strerror(errno)); goto fail_remount_tmpfs; } } /* * Finally, unmount the actual block device from the staging dir */ if (doUnmount(Volume::SEC_STGDIR, force)) { SLOGE("Failed to unmount %s (%s)", SEC_STGDIR, strerror(errno)); goto fail_recreate_bindmount; } SLOGI("%s unmounted sucessfully", getMountpoint()); setState(Volume::State_Idle); mCurrentlyMountedKdev = -1; return 0; /* * Failure handling - try to restore everything back the way it was */ fail_recreate_bindmount: if (mount(SEC_STG_SECIMGDIR, SEC_ASECDIR, "", MS_BIND, NULL)) { SLOGE("Failed to restore bindmount after failure! - Storage will appear offline!"); goto out_nomedia; } fail_remount_tmpfs: if (mount("tmpfs", SEC_STG_SECIMGDIR, "tmpfs", MS_RDONLY, "size=0,mode=0,uid=0,gid=0")) { SLOGE("Failed to restore tmpfs after failure! - Storage will appear offline!"); goto out_nomedia; } fail_republish: if (doMoveMount(SEC_STGDIR, getMountpoint(), force)) { SLOGE("Failed to republish mount after failure! - Storage will appear offline!"); goto out_nomedia; } setState(Volume::State_Mounted); return -1; out_nomedia: setState(Volume::State_NoMedia); return -1; }