1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "EmulatedVolume.h"
18#include "Utils.h"
19
20#include <android-base/stringprintf.h>
21#include <android-base/logging.h>
22#include <cutils/fs.h>
23#include <private/android_filesystem_config.h>
24#include <utils/Timers.h>
25
26#include <fcntl.h>
27#include <stdlib.h>
28#include <sys/mount.h>
29#include <sys/stat.h>
30#include <sys/types.h>
31#include <sys/sysmacros.h>
32#include <sys/wait.h>
33
34using android::base::StringPrintf;
35
36namespace android {
37namespace vold {
38
39static const char* kFusePath = "/system/bin/sdcard";
40
41EmulatedVolume::EmulatedVolume(const std::string& rawPath) :
42        VolumeBase(Type::kEmulated), mFusePid(0) {
43    setId("emulated");
44    mRawPath = rawPath;
45    mLabel = "emulated";
46}
47
48EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device,
49        const std::string& fsUuid) : VolumeBase(Type::kEmulated), mFusePid(0) {
50    setId(StringPrintf("emulated:%u,%u", major(device), minor(device)));
51    mRawPath = rawPath;
52    mLabel = fsUuid;
53}
54
55EmulatedVolume::~EmulatedVolume() {
56}
57
58status_t EmulatedVolume::doMount() {
59    // We could have migrated storage to an adopted private volume, so always
60    // call primary storage "emulated" to avoid media rescans.
61    std::string label = mLabel;
62    if (getMountFlags() & MountFlags::kPrimary) {
63        label = "emulated";
64    }
65
66    mFuseDefault = StringPrintf("/mnt/runtime/default/%s", label.c_str());
67    mFuseRead = StringPrintf("/mnt/runtime/read/%s", label.c_str());
68    mFuseWrite = StringPrintf("/mnt/runtime/write/%s", label.c_str());
69
70    setInternalPath(mRawPath);
71    setPath(StringPrintf("/storage/%s", label.c_str()));
72
73    if (fs_prepare_dir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) ||
74            fs_prepare_dir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) ||
75            fs_prepare_dir(mFuseWrite.c_str(), 0700, AID_ROOT, AID_ROOT)) {
76        PLOG(ERROR) << getId() << " failed to create mount points";
77        return -errno;
78    }
79
80    dev_t before = GetDevice(mFuseWrite);
81
82    if (!(mFusePid = fork())) {
83        if (execl(kFusePath, kFusePath,
84                "-u", "1023", // AID_MEDIA_RW
85                "-g", "1023", // AID_MEDIA_RW
86                "-m",
87                "-w",
88                "-G",
89                "-i",
90                mRawPath.c_str(),
91                label.c_str(),
92                NULL)) {
93            PLOG(ERROR) << "Failed to exec";
94        }
95
96        LOG(ERROR) << "FUSE exiting";
97        _exit(1);
98    }
99
100    if (mFusePid == -1) {
101        PLOG(ERROR) << getId() << " failed to fork";
102        return -errno;
103    }
104
105    nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
106    while (before == GetDevice(mFuseWrite)) {
107        LOG(VERBOSE) << "Waiting for FUSE to spin up...";
108        usleep(50000); // 50ms
109
110        nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME);
111        if (nanoseconds_to_milliseconds(now - start) > 5000) {
112            LOG(WARNING) << "Timed out while waiting for FUSE to spin up";
113            return -ETIMEDOUT;
114        }
115    }
116    /* sdcardfs will have exited already. FUSE will still be running */
117    if (TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, WNOHANG)) == mFusePid)
118        mFusePid = 0;
119
120    return OK;
121}
122
123status_t EmulatedVolume::doUnmount() {
124    // Unmount the storage before we kill the FUSE process. If we kill
125    // the FUSE process first, most file system operations will return
126    // ENOTCONN until the unmount completes. This is an exotic and unusual
127    // error code and might cause broken behaviour in applications.
128    KillProcessesUsingPath(getPath());
129    ForceUnmount(mFuseDefault);
130    ForceUnmount(mFuseRead);
131    ForceUnmount(mFuseWrite);
132
133    if (mFusePid > 0) {
134        kill(mFusePid, SIGTERM);
135        TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0));
136        mFusePid = 0;
137    }
138
139    rmdir(mFuseDefault.c_str());
140    rmdir(mFuseRead.c_str());
141    rmdir(mFuseWrite.c_str());
142
143    mFuseDefault.clear();
144    mFuseRead.clear();
145    mFuseWrite.clear();
146
147    return OK;
148}
149
150}  // namespace vold
151}  // namespace android
152