VolumeManager.cpp revision 8b8f71b1d760411279f3b07a5c97709f052c689e
1914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff/*
2914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * Copyright (C) 2008 The Android Open Source Project
3914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff *
4914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * Licensed under the Apache License, Version 2.0 (the "License");
5914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * you may not use this file except in compliance with the License.
6914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * You may obtain a copy of the License at
7914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff *
8914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff *      http://www.apache.org/licenses/LICENSE-2.0
9914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff *
10914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * Unless required by applicable law or agreed to in writing, software
11914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * distributed under the License is distributed on an "AS IS" BASIS,
12914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * See the License for the specific language governing permissions and
14914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff * limitations under the License.
15914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff */
16914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
17914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff#include <stdio.h>
18914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff#include <stdlib.h>
19914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff#include <string.h>
20cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff#include <errno.h>
21cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff#include <fcntl.h>
22914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff#include <sys/stat.h>
23914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff#include <sys/types.h>
24914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff#include <sys/mount.h>
25914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
26914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff#include <linux/kdev_t.h>
27914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
28914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff#define LOG_TAG "Vold"
29914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
30914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff#include <cutils/log.h>
31914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
32914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff#include <sysutils/NetlinkEvent.h>
33914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
34914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff#include "VolumeManager.h"
35914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff#include "DirectVolume.h"
36914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff#include "ResponseCode.h"
37914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff#include "Loop.h"
38914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff#include "Fat.h"
39914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff#include "Devmapper.h"
40914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
41914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffextern "C" void KillProcessesWithOpenFiles(const char *, int, int, int);
42914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
43914ed90f2c02092474d2db36626734ca1b2cf315Irfan SheriffVolumeManager *VolumeManager::sInstance = NULL;
44914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
45914ed90f2c02092474d2db36626734ca1b2cf315Irfan SheriffVolumeManager *VolumeManager::Instance() {
46914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    if (!sInstance)
47914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        sInstance = new VolumeManager();
48914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    return sInstance;
49914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff}
50cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff
51914ed90f2c02092474d2db36626734ca1b2cf315Irfan SheriffVolumeManager::VolumeManager() {
52914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    mBlockDevices = new BlockDeviceCollection();
53914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    mVolumes = new VolumeCollection();
54914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    mBroadcaster = NULL;
55914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    mUsbMassStorageConnected = false;
56914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff}
57cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff
58914ed90f2c02092474d2db36626734ca1b2cf315Irfan SheriffVolumeManager::~VolumeManager() {
59914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    delete mBlockDevices;
60914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff}
61914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
62914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffint VolumeManager::start() {
63914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    return 0;
64914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff}
65914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
662c08ede34ceb0f847cc9f996db9832f5358f8726Irfan Sheriffint VolumeManager::stop() {
672c08ede34ceb0f847cc9f996db9832f5358f8726Irfan Sheriff    return 0;
682c08ede34ceb0f847cc9f996db9832f5358f8726Irfan Sheriff}
69914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
70914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffint VolumeManager::addVolume(Volume *v) {
71914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    mVolumes->push_back(v);
7241b35884ff68a62f5fc8f65dcc26342d0889113dIrfan Sheriff    return 0;
7341b35884ff68a62f5fc8f65dcc26342d0889113dIrfan Sheriff}
7441b35884ff68a62f5fc8f65dcc26342d0889113dIrfan Sheriff
75914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffvoid VolumeManager::notifyUmsConnected(bool connected) {
76914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    char msg[255];
77914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
78914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    if (connected) {
79914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        mUsbMassStorageConnected = true;
80914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    } else {
81914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        mUsbMassStorageConnected = false;
82914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    }
83914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    snprintf(msg, sizeof(msg), "Share method ums now %s",
84914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff             (connected ? "available" : "unavailable"));
85914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
86914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    getBroadcaster()->sendBroadcast(ResponseCode::ShareAvailabilityChange,
87914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff                                    msg, false);
88914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff}
89914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
90914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffvoid VolumeManager::handleSwitchEvent(NetlinkEvent *evt) {
91914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    const char *devpath = evt->findParam("DEVPATH");
92914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    const char *name = evt->findParam("SWITCH_NAME");
93914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    const char *state = evt->findParam("SWITCH_STATE");
94914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
956bfc88876ab575913299b477528225a4d7bf8232Irfan Sheriff    if (!name || !state) {
966bfc88876ab575913299b477528225a4d7bf8232Irfan Sheriff        LOGW("Switch %s event missing name/state info", devpath);
97914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        return;
98914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    }
99914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
1006bfc88876ab575913299b477528225a4d7bf8232Irfan Sheriff    if (!strcmp(name, "usb_mass_storage")) {
101914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
102914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        if (!strcmp(state, "online"))  {
103914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            notifyUmsConnected(true);
104914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        } else {
105914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            notifyUmsConnected(false);
106cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff        }
107cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff    } else {
108cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff        LOGW("Ignoring unknown switch '%s'", name);
109cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff    }
110cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff}
111914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
112cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriffvoid VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
113914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    const char *devpath = evt->findParam("DEVPATH");
114914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
115914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    /* Lookup a volume to handle this device */
116914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    VolumeCollection::iterator it;
117914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    bool hit = false;
118914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
119914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        if (!(*it)->handleBlockEvent(evt)) {
120914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff#ifdef NETLINK_DEBUG
121914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            LOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
122914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff#endif
123914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            hit = true;
124914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            break;
125cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff        }
126914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    }
127914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
128914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    if (!hit) {
129914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff#ifdef NETLINK_DEBUG
130914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        LOGW("No volumes handled block event for '%s'", devpath);
131914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff#endif
132cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff    }
133914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff}
134914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
135914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffint VolumeManager::listVolumes(SocketClient *cli) {
136914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    VolumeCollection::iterator i;
137914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
138914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
139914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        char *buffer;
140914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        asprintf(&buffer, "%s %s %d",
141914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff                 (*i)->getLabel(), (*i)->getMountpoint(),
142914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff                 (*i)->getState());
143914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
144914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        free(buffer);
145914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    }
146914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
147914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    return 0;
148cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff}
149914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
150914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffint VolumeManager::formatVolume(const char *label) {
151914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    Volume *v = lookupVolume(label);
152914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
153914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    if (!v) {
154914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        errno = ENOENT;
155914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        return -1;
156914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    }
157914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
158914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    return v->formatVol();
159914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff}
160914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
161914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffint VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
162914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    char mountPoint[255];
163914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
164914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
165914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
166914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    if (!isMountpointMounted(mountPoint)) {
167914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        errno = ENOENT;
168bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville        return -1;
169bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville    }
170bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville    snprintf(buffer, maxlen, "/asec/%s", id);
171bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville    return 0;
172bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville}
173bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville
174bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Savilleint VolumeManager::createAsec(const char *id, unsigned int numSectors,
175bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville                              const char *fstype, const char *key, int ownerUid) {
176bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville
1776bfc88876ab575913299b477528225a4d7bf8232Irfan Sheriff    mkdir("/sdcard/android_secure", 0777);
1786bfc88876ab575913299b477528225a4d7bf8232Irfan Sheriff
1796bfc88876ab575913299b477528225a4d7bf8232Irfan Sheriff    if (lookupVolume(id)) {
1806bfc88876ab575913299b477528225a4d7bf8232Irfan Sheriff        LOGE("ASEC volume '%s' currently exists", id);
181cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff        errno = EADDRINUSE;
182914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        return -1;
183bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville    }
184bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville
185bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville    char asecFileName[255];
186bbf30dfd767f823f5f40d14b498e2a593454c5c9Wink Saville    snprintf(asecFileName, sizeof(asecFileName),
187914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff             "/sdcard/android_secure/%s.asec", id);
188914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
189914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    if (!access(asecFileName, F_OK)) {
190914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        LOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
191914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff             asecFileName, strerror(errno));
192cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff        errno = EADDRINUSE;
193914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        return -1;
194914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    }
195914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
196914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    if (Loop::createImageFile(asecFileName, numSectors)) {
197914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        LOGE("ASEC image file creation failed (%s)", strerror(errno));
198914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        return -1;
199914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    }
200914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
201914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    char loopDevice[255];
202914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    if (Loop::create(asecFileName, loopDevice, sizeof(loopDevice))) {
203cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff        LOGE("ASEC loop device creation failed (%s)", strerror(errno));
204914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        unlink(asecFileName);
205914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        return -1;
206914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    }
207914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
208914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    char dmDevice[255];
209914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    bool cleanupDm = false;
210914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
211914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    if (strcmp(key, "none")) {
212914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        if (Devmapper::create(id, loopDevice, key, numSectors, dmDevice,
213914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff                             sizeof(dmDevice))) {
214914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            LOGE("ASEC device mapping failed (%s)", strerror(errno));
215914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            Loop::destroyByDevice(loopDevice);
216914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            unlink(asecFileName);
217914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            return -1;
218914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        }
219914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        cleanupDm = true;
220914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    } else {
221914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        strcpy(dmDevice, loopDevice);
222914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    }
223914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
224914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    if (Fat::format(dmDevice)) {
225914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        LOGE("ASEC FAT format failed (%s)", strerror(errno));
226914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        if (cleanupDm) {
227914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            Devmapper::destroy(id);
228914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        }
229914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        Loop::destroyByDevice(loopDevice);
230914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        unlink(asecFileName);
231914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        return -1;
232914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    }
233914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
234914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    char mountPoint[255];
235914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
236cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff    snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
237914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    if (mkdir(mountPoint, 0777)) {
238914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        if (errno != EEXIST) {
239914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            LOGE("Mountpoint creation failed (%s)", strerror(errno));
240914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            if (cleanupDm) {
241914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff                Devmapper::destroy(id);
242914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            }
243914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            Loop::destroyByDevice(loopDevice);
244914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            unlink(asecFileName);
245914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            return -1;
246914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        }
247914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    }
248914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
249914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    if (Fat::doMount(dmDevice, mountPoint, false, false, ownerUid,
250914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff                     0, 0000, false)) {
251914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff//                     0, 0007, false)) {
252914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        LOGE("ASEC FAT mount failed (%s)", strerror(errno));
253914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        if (cleanupDm) {
254914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            Devmapper::destroy(id);
255914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        }
256914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        Loop::destroyByDevice(loopDevice);
257914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        unlink(asecFileName);
258914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        return -1;
259914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    }
260914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
261914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    return 0;
262914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff}
263914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
264914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffint VolumeManager::finalizeAsec(const char *id) {
265914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    char asecFileName[255];
266914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    char loopDevice[255];
267914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    char mountPoint[255];
268cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff
269914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    snprintf(asecFileName, sizeof(asecFileName),
270914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff             "/sdcard/android_secure/%s.asec", id);
271914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
272914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    if (Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
273914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        LOGE("Unable to finalize %s (%s)", id, strerror(errno));
274914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        return -1;
275914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    }
276914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
277914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
278914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    // XXX:
279914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    if (Fat::doMount(loopDevice, mountPoint, true, true, 0, 0, 0227, false)) {
280914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        LOGE("ASEC finalize mount failed (%s)", strerror(errno));
281914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        return -1;
282914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    }
283914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
284914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    LOGD("ASEC %s finalized", id);
285914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    return 0;
286914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff}
287914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
288914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffint VolumeManager::unmountAsec(const char *id) {
289914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    char asecFileName[255];
290914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    char mountPoint[255];
291cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff
292914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    snprintf(asecFileName, sizeof(asecFileName),
293914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff             "/sdcard/android_secure/%s.asec", id);
294914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
295914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
296cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff    if (isMountpointMounted(mountPoint)) {
297914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        LOGE("Unmount request for ASEC %s when not mounted", id);
298914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        errno = EINVAL;
299914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        return -1;
300914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    }
301914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
302914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    int i, rc;
303914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    for (i = 0; i < 10; i++) {
304914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        rc = umount(mountPoint);
305914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        if (!rc) {
306914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            break;
307914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        }
308914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        if (rc && (errno == EINVAL || errno == ENOENT)) {
309cf99765b6255d73aa4fbc61d5bd78ec65fbd0370Irfan Sheriff            rc = 0;
310914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            break;
311914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        }
312914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        LOGW("ASEC %s unmount attempt %d failed (%s)",
313914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff              id, i +1, strerror(errno));
314914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
315914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        if (i >= 5) {
316914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            KillProcessesWithOpenFiles(mountPoint, (i < 7 ? 0 : 1),
317914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff                                       NULL, 0);
318914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        }
319914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        usleep(1000 * 250);
320914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    }
321914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
322914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    if (rc) {
323914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        LOGE("Failed to unmount ASEC %s", id);
324914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        return -1;
325914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    }
326914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
327914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    if (Devmapper::destroy(id) && errno != ENXIO) {
328914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        LOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
329914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    }
330914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
331914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    char loopDevice[255];
332914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    if (!Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
333914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        Loop::destroyByDevice(loopDevice);
334914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    }
335914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    return 0;
336914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff}
337914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
338914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffint VolumeManager::destroyAsec(const char *id) {
339914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    char asecFileName[255];
340914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    char mountPoint[255];
341914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
342914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    snprintf(asecFileName, sizeof(asecFileName),
343cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff             "/sdcard/android_secure/%s.asec", id);
344cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff    snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
345cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff
346cd672ebf2963e4c448115bac4c80a6659a5904beIrfan Sheriff    if (unmountAsec(id))
347914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff        return -1;
348914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
349914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    unlink(asecFileName);
350914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
351914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    LOGD("ASEC %s destroyed", id);
352914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    return 0;
353914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff}
3547f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff
355914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriffint VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
3562c08ede34ceb0f847cc9f996db9832f5358f8726Irfan Sheriff    char asecFileName[255];
357914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    char mountPoint[255];
3587f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff
359914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    snprintf(asecFileName, sizeof(asecFileName),
3602c08ede34ceb0f847cc9f996db9832f5358f8726Irfan Sheriff             "/sdcard/android_secure/%s.asec", id);
361914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
362914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
363914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff    if (isMountpointMounted(mountPoint)) {
3647f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff        LOGE("ASEC %s already mounted", id);
365b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff        errno = EBUSY;
366b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff        return -1;
367b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff    }
368b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff
369b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff    char loopDevice[255];
370b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff    if (Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
371b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff        if (Loop::create(asecFileName, loopDevice, sizeof(loopDevice))) {
372b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff            LOGE("ASEC loop device creation failed (%s)", strerror(errno));
373b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff            return -1;
374b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff        }
375b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff        LOGD("New loop device created at %s", loopDevice);
376b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff    } else {
377b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff        LOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
378b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff    }
379b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff
380b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff    char dmDevice[255];
381b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff    bool cleanupDm = false;
382b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff    if (strcmp(key, "none")) {
383b9c955664bf300deb11e5aaf88e8ff4d11b26a73Irfan Sheriff        if (Devmapper::lookupActive(id, dmDevice, sizeof(dmDevice))) {
384914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            unsigned int nr_sec = 0;
385914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            int fd;
386914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
387914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            if ((fd = open(loopDevice, O_RDWR)) < 0) {
3887f8a12c75cf2b376fce58fc22b5ecb1b64acf110Irfan Sheriff                LOGE("Failed to open loopdevice (%s)", strerror(errno));
389914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff                Loop::destroyByDevice(loopDevice);
390914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff                return -1;
391914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            }
392914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff
393914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff            if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
394914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff                LOGE("Failed to get loop size (%s)", strerror(errno));
395914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff                Loop::destroyByDevice(loopDevice);
396914ed90f2c02092474d2db36626734ca1b2cf315Irfan Sheriff                close(fd);
397                return -1;
398            }
399            close(fd);
400            if (Devmapper::create(id, loopDevice, key, nr_sec,
401                                  dmDevice, sizeof(dmDevice))) {
402                LOGE("ASEC device mapping failed (%s)", strerror(errno));
403                Loop::destroyByDevice(loopDevice);
404                return -1;
405            }
406            LOGD("New devmapper instance created at %s", dmDevice);
407        } else {
408            LOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
409        }
410        cleanupDm = true;
411    } else {
412        strcpy(dmDevice, loopDevice);
413    }
414
415    if (mkdir(mountPoint, 0777)) {
416        if (errno != EEXIST) {
417            LOGE("Mountpoint creation failed (%s)", strerror(errno));
418            if (cleanupDm) {
419                Devmapper::destroy(id);
420            }
421            Loop::destroyByDevice(loopDevice);
422            return -1;
423        }
424    }
425
426    if (Fat::doMount(dmDevice, mountPoint, true, false, ownerUid, 0,
427                     0222, false)) {
428//                     0227, false)) {
429        LOGE("ASEC mount failed (%s)", strerror(errno));
430        if (cleanupDm) {
431            Devmapper::destroy(id);
432        }
433        Loop::destroyByDevice(loopDevice);
434        return -1;
435    }
436
437    LOGD("ASEC %s mounted", id);
438    return 0;
439}
440
441int VolumeManager::mountVolume(const char *label) {
442    Volume *v = lookupVolume(label);
443
444    if (!v) {
445        errno = ENOENT;
446        return -1;
447    }
448
449    return v->mountVol();
450}
451
452int VolumeManager::shareAvailable(const char *method, bool *avail) {
453
454    if (strcmp(method, "ums")) {
455        errno = ENOSYS;
456        return -1;
457    }
458
459    if (mUsbMassStorageConnected)
460        *avail = true;
461    else
462        *avail = false;
463    return 0;
464}
465
466int VolumeManager::simulate(const char *cmd, const char *arg) {
467
468    if (!strcmp(cmd, "ums")) {
469        if (!strcmp(arg, "connect")) {
470            notifyUmsConnected(true);
471        } else if (!strcmp(arg, "disconnect")) {
472            notifyUmsConnected(false);
473        } else {
474            errno = EINVAL;
475            return -1;
476        }
477    } else {
478        errno = EINVAL;
479        return -1;
480    }
481    return 0;
482}
483
484int VolumeManager::shareVolume(const char *label, const char *method) {
485    Volume *v = lookupVolume(label);
486
487    if (!v) {
488        errno = ENOENT;
489        return -1;
490    }
491
492    /*
493     * Eventually, we'll want to support additional share back-ends,
494     * some of which may work while the media is mounted. For now,
495     * we just support UMS
496     */
497    if (strcmp(method, "ums")) {
498        errno = ENOSYS;
499        return -1;
500    }
501
502    if (v->getState() == Volume::State_NoMedia) {
503        errno = ENODEV;
504        return -1;
505    }
506
507    if (v->getState() != Volume::State_Idle) {
508        // You need to unmount manually befoe sharing
509        errno = EBUSY;
510        return -1;
511    }
512
513    dev_t d = v->getDiskDevice();
514    if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
515        // This volume does not support raw disk access
516        errno = EINVAL;
517        return -1;
518    }
519
520    int fd;
521    char nodepath[255];
522    snprintf(nodepath,
523             sizeof(nodepath), "/dev/block/vold/%d:%d",
524             MAJOR(d), MINOR(d));
525
526    if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file",
527                   O_WRONLY)) < 0) {
528        LOGE("Unable to open ums lunfile (%s)", strerror(errno));
529        return -1;
530    }
531
532    if (write(fd, nodepath, strlen(nodepath)) < 0) {
533        LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
534        close(fd);
535        return -1;
536    }
537
538    close(fd);
539    v->handleVolumeShared();
540    return 0;
541}
542
543int VolumeManager::unshareVolume(const char *label, const char *method) {
544    Volume *v = lookupVolume(label);
545
546    if (!v) {
547        errno = ENOENT;
548        return -1;
549    }
550
551    if (strcmp(method, "ums")) {
552        errno = ENOSYS;
553        return -1;
554    }
555
556    if (v->getState() != Volume::State_Shared) {
557        errno = EINVAL;
558        return -1;
559    }
560
561    dev_t d = v->getDiskDevice();
562
563    int fd;
564    char nodepath[255];
565    snprintf(nodepath,
566             sizeof(nodepath), "/dev/block/vold/%d:%d",
567             MAJOR(d), MINOR(d));
568
569    if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file", O_WRONLY)) < 0) {
570        LOGE("Unable to open ums lunfile (%s)", strerror(errno));
571        return -1;
572    }
573
574    char ch = 0;
575    if (write(fd, &ch, 1) < 0) {
576        LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
577        close(fd);
578        return -1;
579    }
580
581    close(fd);
582    v->handleVolumeUnshared();
583    return 0;
584}
585
586int VolumeManager::unmountVolume(const char *label) {
587    Volume *v = lookupVolume(label);
588
589    if (!v) {
590        errno = ENOENT;
591        return -1;
592    }
593
594    if (v->getState() == Volume::State_NoMedia) {
595        errno = ENODEV;
596        return -1;
597    }
598
599    if (v->getState() != Volume::State_Mounted) {
600        LOGW("Attempt to unmount volume which isn't mounted (%d)\n",
601             v->getState());
602        errno = EBUSY;
603        return -1;
604    }
605
606    return v->unmountVol();
607}
608
609/*
610 * Looks up a volume by it's label or mount-point
611 */
612Volume *VolumeManager::lookupVolume(const char *label) {
613    VolumeCollection::iterator i;
614
615    for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
616        if (label[0] == '/') {
617            if (!strcmp(label, (*i)->getMountpoint()))
618                return (*i);
619        } else {
620            if (!strcmp(label, (*i)->getLabel()))
621                return (*i);
622        }
623    }
624    return NULL;
625}
626
627bool VolumeManager::isMountpointMounted(const char *mp)
628{
629    char device[256];
630    char mount_path[256];
631    char rest[256];
632    FILE *fp;
633    char line[1024];
634
635    if (!(fp = fopen("/proc/mounts", "r"))) {
636        LOGE("Error opening /proc/mounts (%s)", strerror(errno));
637        return false;
638    }
639
640    while(fgets(line, sizeof(line), fp)) {
641        line[strlen(line)-1] = '\0';
642        sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
643        if (!strcmp(mount_path, mp)) {
644            fclose(fp);
645            return true;
646        }
647
648    }
649
650    fclose(fp);
651    return false;
652}
653
654