1f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat/*
2f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * Copyright (C) 2008 The Android Open Source Project
3f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat *
4f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * Licensed under the Apache License, Version 2.0 (the "License");
5f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * you may not use this file except in compliance with the License.
6f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * You may obtain a copy of the License at
7f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat *
8f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat *      http://www.apache.org/licenses/LICENSE-2.0
9f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat *
10f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * Unless required by applicable law or agreed to in writing, software
11f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * distributed under the License is distributed on an "AS IS" BASIS,
12f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * See the License for the specific language governing permissions and
14f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * limitations under the License.
15f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat */
16f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
1749e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat#include <stdlib.h>
18f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#include <string.h>
1949e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat#include <dirent.h>
2049e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat#include <errno.h>
2149e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat#include <fcntl.h>
2249e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
2349e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat#include <sys/types.h>
2449e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat#include <sys/stat.h>
2549e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat#include <sys/types.h>
2649e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat#include <sys/mman.h>
27a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat#include <sys/mount.h>
2829d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall#include <sys/param.h>
29a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
30a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat#include <linux/kdev_t.h>
31a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
32a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat#include <cutils/properties.h>
33a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
342a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat#include <diskconfig/diskconfig.h>
35f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
369092b1dbd31406f6939045fbef70a297b8dbeb62Mike Lockwood#include <private/android_filesystem_config.h>
379092b1dbd31406f6939045fbef70a297b8dbeb62Mike Lockwood
38f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#define LOG_TAG "Vold"
39f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
40ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey#include <cutils/fs.h>
41f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#include <cutils/log.h>
42f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
430de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey#include <string>
440de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey
45f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#include "Volume.h"
46a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat#include "VolumeManager.h"
47a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat#include "ResponseCode.h"
48bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat#include "Fat.h"
49586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat#include "Process.h"
5029d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall#include "cryptfs.h"
51f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
52a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehatextern "C" void dos_partition_dec(void const *pp, struct dos_partition *d);
53a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehatextern "C" void dos_partition_enc(void *pp, struct dos_partition *d);
5449e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
553bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat
563bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat/*
57ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey * Media directory - stuff that only media_rw user can see
583bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat */
59ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkeyconst char *Volume::MEDIA_DIR           = "/mnt/media_rw";
603bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat
613bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat/*
62ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey * Fuse directory - location where fuse wrapped filesystems go
633bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat */
64ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkeyconst char *Volume::FUSE_DIR           = "/storage";
653bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat
663bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat/*
67344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root * Path to external storage where *only* root can access ASEC image files
683bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat */
69344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Rootconst char *Volume::SEC_ASECDIR_EXT   = "/mnt/secure/asec";
703bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat
713bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat/*
72344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root * Path to internal storage where *only* root can access ASEC image files
73344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root */
74344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Rootconst char *Volume::SEC_ASECDIR_INT   = "/data/app-asec";
758c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey
76344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root/*
773bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat * Path to where secure containers are mounted
783bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat */
793bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehatconst char *Volume::ASECDIR           = "/mnt/asec";
803bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat
81fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root/*
82508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root * Path to where OBBs are mounted
83fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root */
84508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Rootconst char *Volume::LOOPDIR           = "/mnt/obb";
85fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
860de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkeyconst char *Volume::BLKID_PATH = "/system/bin/blkid";
870de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey
88a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehatstatic const char *stateToStr(int state) {
89a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    if (state == Volume::State_Init)
90a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return "Initializing";
91a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    else if (state == Volume::State_NoMedia)
92a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return "No-Media";
93a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    else if (state == Volume::State_Idle)
94a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return "Idle-Unmounted";
95a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    else if (state == Volume::State_Pending)
96a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return "Pending";
97a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    else if (state == Volume::State_Mounted)
98a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return "Mounted";
99a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    else if (state == Volume::State_Unmounting)
100a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return "Unmounting";
101a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    else if (state == Volume::State_Checking)
102a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return "Checking";
103a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    else if (state == Volume::State_Formatting)
104a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return "Formatting";
105a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    else if (state == Volume::State_Shared)
106a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return "Shared-Unmounted";
107a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    else if (state == Volume::State_SharedMnt)
108a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return "Shared-Mounted";
109a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    else
110a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return "Unknown-Error";
111a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat}
11249e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
113ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff SharkeyVolume::Volume(VolumeManager *vm, const fstab_rec* rec, int flags) {
114a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    mVm = vm;
115d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    mDebug = false;
116ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    mLabel = strdup(rec->label);
1170de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    mUuid = NULL;
1180de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    mUserLabel = NULL;
119f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    mState = Volume::State_Init;
120ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    mFlags = flags;
121a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    mCurrentlyMountedKdev = -1;
122ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    mPartIdx = rec->partnum;
123507d31b86b38dffe7c60ca5c54b5e631f5a7cab3Joseph Lehrer    mRetryMount = false;
124f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat}
125f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
126f1b736bc5605e92e917ab27f5abf3ba839be2270San MehatVolume::~Volume() {
127f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    free(mLabel);
1280de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    free(mUuid);
1290de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    free(mUserLabel);
130cb4dac8a5243f6673b0590019b5b28a01bd3e343San Mehat}
131cb4dac8a5243f6673b0590019b5b28a01bd3e343San Mehat
132d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehatvoid Volume::setDebug(bool enable) {
133d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    mDebug = enable;
134d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat}
135d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
136a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehatdev_t Volume::getDiskDevice() {
137a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    return MKDEV(0, 0);
138a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat};
139a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
1402dfe297ec47559dbe2297a72bea71cf515c03797Mike Lockwooddev_t Volume::getShareDevice() {
1412dfe297ec47559dbe2297a72bea71cf515c03797Mike Lockwood    return getDiskDevice();
1422dfe297ec47559dbe2297a72bea71cf515c03797Mike Lockwood}
1432dfe297ec47559dbe2297a72bea71cf515c03797Mike Lockwood
144a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehatvoid Volume::handleVolumeShared() {
145a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat}
146a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
147a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehatvoid Volume::handleVolumeUnshared() {
148a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat}
149a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
1503e971277db0d87652af5622c989233e7159ab909Mark Salyzynint Volume::handleBlockEvent(NetlinkEvent * /*evt*/) {
151f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    errno = ENOSYS;
152f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    return -1;
153f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat}
154f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
1550de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkeyvoid Volume::setUuid(const char* uuid) {
1560de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    char msg[256];
1570de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey
1580de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    if (mUuid) {
1590de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey        free(mUuid);
1600de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    }
1610de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey
1620de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    if (uuid) {
1630de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey        mUuid = strdup(uuid);
1640de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey        snprintf(msg, sizeof(msg), "%s %s \"%s\"", getLabel(),
1650de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey                getFuseMountpoint(), mUuid);
1660de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    } else {
1670de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey        mUuid = NULL;
1680de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey        snprintf(msg, sizeof(msg), "%s %s", getLabel(), getFuseMountpoint());
1690de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    }
1700de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey
1710de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeUuidChange, msg,
1720de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey            false);
1730de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey}
1740de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey
1750de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkeyvoid Volume::setUserLabel(const char* userLabel) {
1760de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    char msg[256];
1770de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey
1780de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    if (mUserLabel) {
1790de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey        free(mUserLabel);
1800de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    }
1810de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey
1820de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    if (userLabel) {
1830de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey        mUserLabel = strdup(userLabel);
1840de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey        snprintf(msg, sizeof(msg), "%s %s \"%s\"", getLabel(),
1850de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey                getFuseMountpoint(), mUserLabel);
1860de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    } else {
1870de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey        mUserLabel = NULL;
1880de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey        snprintf(msg, sizeof(msg), "%s %s", getLabel(), getFuseMountpoint());
1890de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    }
1900de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey
1910de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeUserLabelChange,
1920de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey            msg, false);
1930de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey}
1940de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey
195f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehatvoid Volume::setState(int state) {
196a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    char msg[255];
197a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    int oldState = mState;
198a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
199a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    if (oldState == state) {
20097ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGW("Duplicate state (%d)\n", state);
201a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return;
202a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
203a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
204507d31b86b38dffe7c60ca5c54b5e631f5a7cab3Joseph Lehrer    if ((oldState == Volume::State_Pending) && (state != Volume::State_Idle)) {
205507d31b86b38dffe7c60ca5c54b5e631f5a7cab3Joseph Lehrer        mRetryMount = false;
206507d31b86b38dffe7c60ca5c54b5e631f5a7cab3Joseph Lehrer    }
207507d31b86b38dffe7c60ca5c54b5e631f5a7cab3Joseph Lehrer
208f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat    mState = state;
209a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
21097ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat    SLOGD("Volume %s state changing %d (%s) -> %d (%s)", mLabel,
211a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat         oldState, stateToStr(oldState), mState, stateToStr(mState));
212a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    snprintf(msg, sizeof(msg),
213a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat             "Volume %s %s state changed from %d (%s) to %d (%s)", getLabel(),
214ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey             getFuseMountpoint(), oldState, stateToStr(oldState), mState,
215a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat             stateToStr(mState));
216a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
217a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeStateChange,
218a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat                                         msg, false);
219f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat}
22049e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
221dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehatint Volume::createDeviceNode(const char *path, int major, int minor) {
222dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat    mode_t mode = 0660 | S_IFBLK;
223dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat    dev_t dev = (major << 8) | minor;
224dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat    if (mknod(path, mode, dev) < 0) {
225dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat        if (errno != EEXIST) {
226dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat            return -1;
227dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat        }
228dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat    }
229dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat    return 0;
230dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat}
231dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat
2329caab76c6b5aefdeeb1715a3695491ca793b8c18Ken Sumrallint Volume::formatVol(bool wipe) {
23349e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
234a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    if (getState() == Volume::State_NoMedia) {
235a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        errno = ENODEV;
23649e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        return -1;
237a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    } else if (getState() != Volume::State_Idle) {
238a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        errno = EBUSY;
239a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return -1;
240a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
241a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
242a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    if (isMountpointMounted(getMountpoint())) {
24397ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGW("Volume is idle but appears to be mounted - fixing");
244a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        setState(Volume::State_Mounted);
245a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        // mCurrentlyMountedKdev = XXX
246a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        errno = EBUSY;
247a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return -1;
248a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
249a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
250a4886f1f8ed72e24a302a91a0ab18bc54b6f585eMike Lockwood    bool formatEntireDevice = (mPartIdx == -1);
251a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    char devicePath[255];
252a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    dev_t diskNode = getDiskDevice();
253cc21d6ea5881a9f576296317bde8d818b3e4fc01Blair Prescott    dev_t partNode =
254cc21d6ea5881a9f576296317bde8d818b3e4fc01Blair Prescott        MKDEV(MAJOR(diskNode),
255cc21d6ea5881a9f576296317bde8d818b3e4fc01Blair Prescott              MINOR(diskNode) + (formatEntireDevice ? 1 : mPartIdx));
256a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
2572a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    setState(Volume::State_Formatting);
258a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
25964382de1f93b84ca59f607da4b4fdbd77f1af67dChih-Wei Huang    int ret = -1;
260a4886f1f8ed72e24a302a91a0ab18bc54b6f585eMike Lockwood    // Only initialize the MBR if we are formatting the entire device
261a4886f1f8ed72e24a302a91a0ab18bc54b6f585eMike Lockwood    if (formatEntireDevice) {
262a4886f1f8ed72e24a302a91a0ab18bc54b6f585eMike Lockwood        sprintf(devicePath, "/dev/block/vold/%d:%d",
263346c5b20cbbced7edacf240015c4a89e5b2ca44fColin Cross                major(diskNode), minor(diskNode));
264a4886f1f8ed72e24a302a91a0ab18bc54b6f585eMike Lockwood
265a4886f1f8ed72e24a302a91a0ab18bc54b6f585eMike Lockwood        if (initializeMbr(devicePath)) {
266a4886f1f8ed72e24a302a91a0ab18bc54b6f585eMike Lockwood            SLOGE("Failed to initialize MBR (%s)", strerror(errno));
267a4886f1f8ed72e24a302a91a0ab18bc54b6f585eMike Lockwood            goto err;
268a4886f1f8ed72e24a302a91a0ab18bc54b6f585eMike Lockwood        }
269a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
270a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
271a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    sprintf(devicePath, "/dev/block/vold/%d:%d",
272346c5b20cbbced7edacf240015c4a89e5b2ca44fColin Cross            major(partNode), minor(partNode));
273a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
274a4886f1f8ed72e24a302a91a0ab18bc54b6f585eMike Lockwood    if (mDebug) {
275a4886f1f8ed72e24a302a91a0ab18bc54b6f585eMike Lockwood        SLOGI("Formatting volume %s (%s)", getLabel(), devicePath);
276a4886f1f8ed72e24a302a91a0ab18bc54b6f585eMike Lockwood    }
277a4886f1f8ed72e24a302a91a0ab18bc54b6f585eMike Lockwood
2789caab76c6b5aefdeeb1715a3695491ca793b8c18Ken Sumrall    if (Fat::format(devicePath, 0, wipe)) {
27997ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Failed to format (%s)", strerror(errno));
280a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        goto err;
281a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
282a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
28364382de1f93b84ca59f607da4b4fdbd77f1af67dChih-Wei Huang    ret = 0;
28464382de1f93b84ca59f607da4b4fdbd77f1af67dChih-Wei Huang
285a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehaterr:
28664382de1f93b84ca59f607da4b4fdbd77f1af67dChih-Wei Huang    setState(Volume::State_Idle);
28764382de1f93b84ca59f607da4b4fdbd77f1af67dChih-Wei Huang    return ret;
288a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat}
289a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
290a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehatbool Volume::isMountpointMounted(const char *path) {
291a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    char device[256];
292a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    char mount_path[256];
293a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    char rest[256];
294a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    FILE *fp;
295a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    char line[1024];
296a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
297a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    if (!(fp = fopen("/proc/mounts", "r"))) {
29897ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
299a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return false;
30049e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    }
30149e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
302a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    while(fgets(line, sizeof(line), fp)) {
303a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        line[strlen(line)-1] = '\0';
304a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
305a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        if (!strcmp(mount_path, path)) {
306a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat            fclose(fp);
307a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat            return true;
308a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        }
309a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
310dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat
311a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    fclose(fp);
312a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    return false;
313a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat}
314a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
315a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehatint Volume::mountVol() {
316a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    dev_t deviceNodes[4];
317a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    int n, i, rc = 0;
318a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    char errmsg[255];
319ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey
320ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    int flags = getFlags();
321ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    bool providesAsec = (flags & VOL_PROVIDES_ASEC) != 0;
322ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey
323ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    // TODO: handle "bind" style mounts, for emulated storage
324ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey
32529d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    char decrypt_state[PROPERTY_VALUE_MAX];
32629d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    char crypto_state[PROPERTY_VALUE_MAX];
32729d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    char encrypt_progress[PROPERTY_VALUE_MAX];
32829d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall
32929d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    property_get("vold.decrypt", decrypt_state, "");
33029d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    property_get("vold.encrypt_progress", encrypt_progress, "");
33129d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall
33229d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    /* Don't try to mount the volumes if we have not yet entered the disk password
33329d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall     * or are in the process of encrypting.
33429d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall     */
33529d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    if ((getState() == Volume::State_NoMedia) ||
336ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey        ((!strcmp(decrypt_state, "1") || encrypt_progress[0]) && providesAsec)) {
337a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        snprintf(errmsg, sizeof(errmsg),
338a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat                 "Volume %s %s mount failed - no media",
339ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey                 getLabel(), getFuseMountpoint());
340a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        mVm->getBroadcaster()->sendBroadcast(
341a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat                                         ResponseCode::VolumeMountFailedNoMedia,
342a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat                                         errmsg, false);
343a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        errno = ENODEV;
344a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return -1;
345a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    } else if (getState() != Volume::State_Idle) {
346a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        errno = EBUSY;
347507d31b86b38dffe7c60ca5c54b5e631f5a7cab3Joseph Lehrer        if (getState() == Volume::State_Pending) {
348507d31b86b38dffe7c60ca5c54b5e631f5a7cab3Joseph Lehrer            mRetryMount = true;
349507d31b86b38dffe7c60ca5c54b5e631f5a7cab3Joseph Lehrer        }
35049e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        return -1;
35149e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    }
35249e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
353a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    if (isMountpointMounted(getMountpoint())) {
35497ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGW("Volume is idle but appears to be mounted - fixing");
355a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        setState(Volume::State_Mounted);
356a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        // mCurrentlyMountedKdev = XXX
357a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return 0;
358a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
359a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
360a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    n = getDeviceNodes((dev_t *) &deviceNodes, 4);
361a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    if (!n) {
36297ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Failed to get device nodes (%s)\n", strerror(errno));
36349e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat        return -1;
36449e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    }
36549e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
36629d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    /* If we're running encrypted, and the volume is marked as encryptable and nonremovable,
367ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey     * and also marked as providing Asec storage, then we need to decrypt
36829d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall     * that partition, and update the volume object to point to it's new decrypted
36929d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall     * block device
37029d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall     */
37129d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    property_get("ro.crypto.state", crypto_state, "");
372ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    if (providesAsec &&
37329d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall        ((flags & (VOL_NONREMOVABLE | VOL_ENCRYPTABLE))==(VOL_NONREMOVABLE | VOL_ENCRYPTABLE)) &&
37429d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall        !strcmp(crypto_state, "encrypted") && !isDecrypted()) {
37529d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall       char new_sys_path[MAXPATHLEN];
37629d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall       char nodepath[256];
37729d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall       int new_major, new_minor;
37829d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall
37929d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall       if (n != 1) {
38029d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall           /* We only expect one device node returned when mounting encryptable volumes */
38159846b654e8b4a22a1be11cd21d6c5b81375abd2Colin Cross           SLOGE("Too many device nodes returned when mounting %s\n", getMountpoint());
38229d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall           return -1;
38329d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall       }
38429d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall
38529d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall       if (cryptfs_setup_volume(getLabel(), MAJOR(deviceNodes[0]), MINOR(deviceNodes[0]),
38629d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall                                new_sys_path, sizeof(new_sys_path),
38729d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall                                &new_major, &new_minor)) {
38859846b654e8b4a22a1be11cd21d6c5b81375abd2Colin Cross           SLOGE("Cannot setup encryption mapping for %s\n", getMountpoint());
38929d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall           return -1;
39029d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall       }
39129d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall       /* We now have the new sysfs path for the decrypted block device, and the
39229d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall        * majore and minor numbers for it.  So, create the device, update the
39329d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall        * path to the new sysfs path, and continue.
39429d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall        */
39529d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall        snprintf(nodepath,
39629d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall                 sizeof(nodepath), "/dev/block/vold/%d:%d",
39729d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall                 new_major, new_minor);
39829d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall        if (createDeviceNode(nodepath, new_major, new_minor)) {
39929d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall            SLOGE("Error making device node '%s' (%s)", nodepath,
40029d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall                                                       strerror(errno));
40129d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall        }
40229d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall
40329d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall        // Todo: Either create sys filename from nodepath, or pass in bogus path so
40429d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall        //       vold ignores state changes on this internal device.
40529d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall        updateDeviceInfo(nodepath, new_major, new_minor);
40629d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall
40729d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall        /* Get the device nodes again, because they just changed */
40829d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall        n = getDeviceNodes((dev_t *) &deviceNodes, 4);
40929d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall        if (!n) {
41029d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall            SLOGE("Failed to get device nodes (%s)\n", strerror(errno));
41129d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall            return -1;
41229d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall        }
41329d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall    }
41429d8da8cefa99e436c13295d4c9bad060ca18a6dKen Sumrall
415a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    for (i = 0; i < n; i++) {
416a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        char devicePath[255];
417dd9b8e92aaf330b48ddb40a7380588ef92b53de6San Mehat
418346c5b20cbbced7edacf240015c4a89e5b2ca44fColin Cross        sprintf(devicePath, "/dev/block/vold/%d:%d", major(deviceNodes[i]),
419346c5b20cbbced7edacf240015c4a89e5b2ca44fColin Cross                minor(deviceNodes[i]));
420a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
42197ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGI("%s being considered for volume %s\n", devicePath, getLabel());
422a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
423a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        errno = 0;
424bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat        setState(Volume::State_Checking);
425bf04185c88161f13118b9975cdff7967d49a4fa0San Mehat
4263bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat        if (Fat::check(devicePath)) {
427a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat            if (errno == ENODATA) {
42897ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat                SLOGW("%s does not contain a FAT filesystem\n", devicePath);
429a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat                continue;
430a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat            }
431eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            errno = EIO;
432eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            /* Badness - abort the mount */
43397ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat            SLOGE("%s failed FS checks (%s)", devicePath, strerror(errno));
434eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            setState(Volume::State_Idle);
435eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            return -1;
436a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        }
437a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
438a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        errno = 0;
4399092b1dbd31406f6939045fbef70a297b8dbeb62Mike Lockwood        int gid;
4409092b1dbd31406f6939045fbef70a297b8dbeb62Mike Lockwood
441ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey        if (Fat::doMount(devicePath, getMountpoint(), false, false, false,
442ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey                AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) {
44397ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat            SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno));
4443bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat            continue;
445a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        }
446a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
4470de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey        extractMetadata(devicePath);
448cb4dac8a5243f6673b0590019b5b28a01bd3e343San Mehat
449ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey        if (providesAsec && mountAsecExternal() != 0) {
450ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey            SLOGE("Failed to mount secure area (%s)", strerror(errno));
451ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey            umount(getMountpoint());
4523bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat            setState(Volume::State_Idle);
4533bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat            return -1;
4543bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat        }
4553bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat
456ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey        char service[64];
457ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey        snprintf(service, 64, "fuse_%s", getLabel());
458ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey        property_set("ctl.start", service);
459ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey
4603bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat        setState(Volume::State_Mounted);
4613bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat        mCurrentlyMountedKdev = deviceNodes[i];
4623bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat        return 0;
463a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
464a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
46597ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat    SLOGE("Volume %s found no suitable devices for mounting :(\n", getLabel());
46649e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat    setState(Volume::State_Idle);
467a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
468eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    return -1;
469a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat}
470a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
471ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkeyint Volume::mountAsecExternal() {
472ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    char legacy_path[PATH_MAX];
473ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    char secure_path[PATH_MAX];
4743bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat
475ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    snprintf(legacy_path, PATH_MAX, "%s/android_secure", getMountpoint());
476ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    snprintf(secure_path, PATH_MAX, "%s/.android_secure", getMountpoint());
477a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
478ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    // Recover legacy secure path
479ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    if (!access(legacy_path, R_OK | X_OK) && access(secure_path, R_OK | X_OK)) {
480ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey        if (rename(legacy_path, secure_path)) {
481ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey            SLOGE("Failed to rename legacy asec dir (%s)", strerror(errno));
4823bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat        }
4833bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat    }
4843bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat
485ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    if (fs_prepare_dir(secure_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) != 0) {
4868c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey        SLOGW("fs_prepare_dir failed: %s", strerror(errno));
487a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return -1;
488a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
489a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
490ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    if (mount(secure_path, SEC_ASECDIR_EXT, "", MS_BIND, NULL)) {
491ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey        SLOGE("Failed to bind mount points %s -> %s (%s)", secure_path,
492ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey                SEC_ASECDIR_EXT, strerror(errno));
4933bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat        return -1;
4943bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat    }
4953bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat
4963bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat    return 0;
4973bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat}
4983bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat
4993bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehatint Volume::doUnmount(const char *path, bool force) {
5003bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat    int retries = 10;
5013bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat
502d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    if (mDebug) {
50397ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGD("Unmounting {%s}, force = %d", path, force);
504d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    }
505d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
5063bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat    while (retries--) {
5073bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat        if (!umount(path) || errno == EINVAL || errno == ENOENT) {
50897ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat            SLOGI("%s sucessfully unmounted", path);
5093bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat            return 0;
5103bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat        }
5118c940ef7dbd423cadc92982b44a65ed1014389e2San Mehat
5124ba8948dc16463053e21cda5744f519a555080d0San Mehat        int action = 0;
5138c940ef7dbd423cadc92982b44a65ed1014389e2San Mehat
5144ba8948dc16463053e21cda5744f519a555080d0San Mehat        if (force) {
5153bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat            if (retries == 1) {
5164ba8948dc16463053e21cda5744f519a555080d0San Mehat                action = 2; // SIGKILL
5173bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat            } else if (retries == 2) {
5184ba8948dc16463053e21cda5744f519a555080d0San Mehat                action = 1; // SIGHUP
5194ba8948dc16463053e21cda5744f519a555080d0San Mehat            }
5204ba8948dc16463053e21cda5744f519a555080d0San Mehat        }
5218c940ef7dbd423cadc92982b44a65ed1014389e2San Mehat
52297ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGW("Failed to unmount %s (%s, retries %d, action %d)",
5233bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat                path, strerror(errno), retries, action);
5243bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat
5253bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat        Process::killProcessesWithOpenFiles(path, action);
5264ba8948dc16463053e21cda5744f519a555080d0San Mehat        usleep(1000*1000);
527a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
5283bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat    errno = EBUSY;
52997ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat    SLOGE("Giving up on unmount %s (%s)", path, strerror(errno));
5303bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat    return -1;
5313bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat}
532a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
5330b8b59719357fb80c330442787f7d5b1e332263bKen Sumrallint Volume::unmountVol(bool force, bool revert) {
5343bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat    int i, rc;
5353bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat
536ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    int flags = getFlags();
537ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    bool providesAsec = (flags & VOL_PROVIDES_ASEC) != 0;
538ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey
5393bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat    if (getState() != Volume::State_Mounted) {
54097ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Volume %s unmount request when not mounted", getLabel());
5413bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat        errno = EINVAL;
542319b1043bbbd410aa2d572d88b5936f26072d026Ken Sumrall        return UNMOUNT_NOT_MOUNTED_ERR;
5433bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat    }
5443bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat
5453bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat    setState(Volume::State_Unmounting);
5463bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat    usleep(1000 * 1000); // Give the framework some time to react
5473bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat
548ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    char service[64];
549ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    snprintf(service, 64, "fuse_%s", getLabel());
550ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    property_set("ctl.stop", service);
551ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    /* Give it a chance to stop.  I wish we had a synchronous way to determine this... */
552ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    sleep(1);
553ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey
554ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    // TODO: determine failure mode if FUSE times out
555ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey
556ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    if (providesAsec && doUnmount(Volume::SEC_ASECDIR_EXT, force) != 0) {
557ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey        SLOGE("Failed to unmount secure area on %s (%s)", getMountpoint(), strerror(errno));
558ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey        goto out_mounted;
5593bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat    }
5603bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat
561ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    /* Now that the fuse daemon is dead, unmount it */
562ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    if (doUnmount(getFuseMountpoint(), force) != 0) {
563ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey        SLOGE("Failed to unmount %s (%s)", getFuseMountpoint(), strerror(errno));
564ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey        goto fail_remount_secure;
5653bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat    }
5663bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat
567ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    /* Unmount the real sd card */
568ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    if (doUnmount(getMountpoint(), force) != 0) {
569ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey        SLOGE("Failed to unmount %s (%s)", getMountpoint(), strerror(errno));
570ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey        goto fail_remount_secure;
5713bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat    }
5723bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat
573ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    SLOGI("%s unmounted successfully", getMountpoint());
5743bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat
5750b8b59719357fb80c330442787f7d5b1e332263bKen Sumrall    /* If this is an encrypted volume, and we've been asked to undo
5760b8b59719357fb80c330442787f7d5b1e332263bKen Sumrall     * the crypto mapping, then revert the dm-crypt mapping, and revert
5770b8b59719357fb80c330442787f7d5b1e332263bKen Sumrall     * the device info to the original values.
5780b8b59719357fb80c330442787f7d5b1e332263bKen Sumrall     */
5790b8b59719357fb80c330442787f7d5b1e332263bKen Sumrall    if (revert && isDecrypted()) {
5800b8b59719357fb80c330442787f7d5b1e332263bKen Sumrall        cryptfs_revert_volume(getLabel());
5810b8b59719357fb80c330442787f7d5b1e332263bKen Sumrall        revertDeviceInfo();
5820b8b59719357fb80c330442787f7d5b1e332263bKen Sumrall        SLOGI("Encrypted volume %s reverted successfully", getMountpoint());
5830b8b59719357fb80c330442787f7d5b1e332263bKen Sumrall    }
5840b8b59719357fb80c330442787f7d5b1e332263bKen Sumrall
5850de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    setUuid(NULL);
5860de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    setUserLabel(NULL);
5873bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat    setState(Volume::State_Idle);
5883bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat    mCurrentlyMountedKdev = -1;
5893bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat    return 0;
5903bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat
591ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkeyfail_remount_secure:
592ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey    if (providesAsec && mountAsecExternal() != 0) {
593ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey        SLOGE("Failed to remount secure area (%s)", strerror(errno));
5943bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat        goto out_nomedia;
595a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
596a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
597ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkeyout_mounted:
598a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    setState(Volume::State_Mounted);
599a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    return -1;
6003bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat
6013bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehatout_nomedia:
6023bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat    setState(Volume::State_NoMedia);
6033bb6020e461e8872e8df0775cba6eb32e06b93ecSan Mehat    return -1;
604a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat}
605ba6ae8db137d012c9b8e11f9f8321c7771698e92Jeff Sharkey
606a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehatint Volume::initializeMbr(const char *deviceNode) {
6072a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    struct disk_info dinfo;
608a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
6092a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    memset(&dinfo, 0, sizeof(dinfo));
610a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
6112a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    if (!(dinfo.part_lst = (struct part_info *) malloc(MAX_NUM_PARTS * sizeof(struct part_info)))) {
61297ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Failed to malloc prt_lst");
613a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat        return -1;
614a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
615a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
6162a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    memset(dinfo.part_lst, 0, MAX_NUM_PARTS * sizeof(struct part_info));
6172a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    dinfo.device = strdup(deviceNode);
6182a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    dinfo.scheme = PART_SCHEME_MBR;
6192a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    dinfo.sect_size = 512;
6202a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    dinfo.skip_lba = 2048;
6212a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    dinfo.num_lba = 0;
6222a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    dinfo.num_parts = 1;
623a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
6242a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    struct part_info *pinfo = &dinfo.part_lst[0];
625a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
6262a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    pinfo->name = strdup("android_sdcard");
6272a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    pinfo->flags |= PART_ACTIVE_FLAG;
6282a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    pinfo->type = PC_PART_TYPE_FAT32;
6292a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    pinfo->len_kb = -1;
630a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
6312a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    int rc = apply_disk_config(&dinfo, 0);
632a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
6332a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    if (rc) {
63497ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat        SLOGE("Failed to apply disk configuration (%d)", rc);
6352a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat        goto out;
636a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
6372a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat
6382a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat out:
6392a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    free(pinfo->name);
6402a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    free(dinfo.device);
6412a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    free(dinfo.part_lst);
6422a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat
6432a5b8ce09b8836a8463ef9beaaff865c36ca5e6aSan Mehat    return rc;
644a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat}
6450de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey
6460de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey/*
6470de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey * Use blkid to extract UUID and label from device, since it handles many
6480de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey * obscure edge cases around partition types and formats. Always broadcasts
6490de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey * updated metadata values.
6500de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey */
6510de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkeyint Volume::extractMetadata(const char* devicePath) {
6520de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    int res = 0;
6530de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey
6540de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    std::string cmd;
6550de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    cmd = BLKID_PATH;
6560de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    cmd += " -c /dev/null ";
6570de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    cmd += devicePath;
6580de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey
6590de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    FILE* fp = popen(cmd.c_str(), "r");
6600de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    if (!fp) {
6610de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey        ALOGE("Failed to run %s: %s", cmd.c_str(), strerror(errno));
6620de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey        res = -1;
6630de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey        goto done;
6640de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    }
6650de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey
6660de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    char line[1024];
6670de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    char value[128];
6680de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    if (fgets(line, sizeof(line), fp) != NULL) {
6698c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey        ALOGD("blkid identified as %s", line);
6700de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey
6716bcd362edd1f0ad97807276ff7f9f16991df99a4Jeff Sharkey        char* start = strstr(line, "UUID=");
6726bcd362edd1f0ad97807276ff7f9f16991df99a4Jeff Sharkey        if (start != NULL && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
6730de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey            setUuid(value);
6740de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey        } else {
6750de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey            setUuid(NULL);
6760de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey        }
6770de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey
6786bcd362edd1f0ad97807276ff7f9f16991df99a4Jeff Sharkey        start = strstr(line, "LABEL=");
6796bcd362edd1f0ad97807276ff7f9f16991df99a4Jeff Sharkey        if (start != NULL && sscanf(start + 6, "\"%127[^\"]\"", value) == 1) {
6800de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey            setUserLabel(value);
6810de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey        } else {
6820de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey            setUserLabel(NULL);
6830de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey        }
6840de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    } else {
6858c2c15b1c611708c85b3f1ba86b6db79c5c004d5Jeff Sharkey        ALOGW("blkid failed to identify %s", devicePath);
6860de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey        res = -1;
6870de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    }
6880de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey
6890de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    pclose(fp);
6900de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey
6910de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkeydone:
6920de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    if (res == -1) {
6930de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey        setUuid(NULL);
6940de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey        setUserLabel(NULL);
6950de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    }
6960de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey    return res;
6970de365fc0af30ae48c2037e1057f2a813029a618Jeff Sharkey}
698