1deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey/*
2deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey * Copyright (C) 2015 The Android Open Source Project
3deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey *
4deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
5deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey * you may not use this file except in compliance with the License.
6deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey * You may obtain a copy of the License at
7deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey *
8deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
9deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey *
10deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey * Unless required by applicable law or agreed to in writing, software
11deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
12deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey * See the License for the specific language governing permissions and
14deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey * limitations under the License.
15deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey */
16deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey
17deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey#include "EmulatedVolume.h"
18deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey#include "Utils.h"
19deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey
207e128fbe212c64492afa98bfd6d7fab6f1956831Elliott Hughes#include <android-base/stringprintf.h>
217e128fbe212c64492afa98bfd6d7fab6f1956831Elliott Hughes#include <android-base/logging.h>
22deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey#include <cutils/fs.h>
23deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey#include <private/android_filesystem_config.h>
24deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey
25deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey#include <fcntl.h>
26deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey#include <stdlib.h>
27deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey#include <sys/mount.h>
28deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey#include <sys/stat.h>
29deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey#include <sys/types.h>
300e08e84df0d0b555cf20e3bbe68bb4da7c287012Elliott Hughes#include <sys/sysmacros.h>
31deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey#include <sys/wait.h>
32deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey
33ae9e8903375e13028b140e86fcc68c6e152b6f43Dan Albertusing android::base::StringPrintf;
34ae9e8903375e13028b140e86fcc68c6e152b6f43Dan Albert
35deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkeynamespace android {
36deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkeynamespace vold {
37deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey
38deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkeystatic const char* kFusePath = "/system/bin/sdcard";
39deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey
403161fb3702830b586b2e36fa9ca4519f59f951b4Jeff SharkeyEmulatedVolume::EmulatedVolume(const std::string& rawPath) :
413161fb3702830b586b2e36fa9ca4519f59f951b4Jeff Sharkey        VolumeBase(Type::kEmulated), mFusePid(0) {
423161fb3702830b586b2e36fa9ca4519f59f951b4Jeff Sharkey    setId("emulated");
433161fb3702830b586b2e36fa9ca4519f59f951b4Jeff Sharkey    mRawPath = rawPath;
4466270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey    mLabel = "emulated";
453161fb3702830b586b2e36fa9ca4519f59f951b4Jeff Sharkey}
46deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey
473161fb3702830b586b2e36fa9ca4519f59f951b4Jeff SharkeyEmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device,
483161fb3702830b586b2e36fa9ca4519f59f951b4Jeff Sharkey        const std::string& fsUuid) : VolumeBase(Type::kEmulated), mFusePid(0) {
493161fb3702830b586b2e36fa9ca4519f59f951b4Jeff Sharkey    setId(StringPrintf("emulated:%u,%u", major(device), minor(device)));
50deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey    mRawPath = rawPath;
5166270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey    mLabel = fsUuid;
52deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey}
53deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey
54deb240573754daf36fa8ea10a05240f9f31e7b2cJeff SharkeyEmulatedVolume::~EmulatedVolume() {
55deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey}
56deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey
57deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkeystatus_t EmulatedVolume::doMount() {
5881f55c6dc1a14ed68e404fa3a2c244dd343e4990Jeff Sharkey    // We could have migrated storage to an adopted private volume, so always
5981f55c6dc1a14ed68e404fa3a2c244dd343e4990Jeff Sharkey    // call primary storage "emulated" to avoid media rescans.
6081f55c6dc1a14ed68e404fa3a2c244dd343e4990Jeff Sharkey    std::string label = mLabel;
6181f55c6dc1a14ed68e404fa3a2c244dd343e4990Jeff Sharkey    if (getMountFlags() & MountFlags::kPrimary) {
6281f55c6dc1a14ed68e404fa3a2c244dd343e4990Jeff Sharkey        label = "emulated";
6381f55c6dc1a14ed68e404fa3a2c244dd343e4990Jeff Sharkey    }
6481f55c6dc1a14ed68e404fa3a2c244dd343e4990Jeff Sharkey
651bd078fa7b5ca613cb3e793d67ccd86d2602787dJeff Sharkey    mFuseDefault = StringPrintf("/mnt/runtime/default/%s", label.c_str());
661bd078fa7b5ca613cb3e793d67ccd86d2602787dJeff Sharkey    mFuseRead = StringPrintf("/mnt/runtime/read/%s", label.c_str());
671bd078fa7b5ca613cb3e793d67ccd86d2602787dJeff Sharkey    mFuseWrite = StringPrintf("/mnt/runtime/write/%s", label.c_str());
6866270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey
6966270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey    setInternalPath(mRawPath);
7081f55c6dc1a14ed68e404fa3a2c244dd343e4990Jeff Sharkey    setPath(StringPrintf("/storage/%s", label.c_str()));
7166270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey
7266270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey    if (fs_prepare_dir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) ||
7366270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey            fs_prepare_dir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) ||
7466270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey            fs_prepare_dir(mFuseWrite.c_str(), 0700, AID_ROOT, AID_ROOT)) {
7566270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey        PLOG(ERROR) << getId() << " failed to create mount points";
76deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey        return -errno;
77deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey    }
78deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey
7966270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey    dev_t before = GetDevice(mFuseWrite);
8036801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
81deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey    if (!(mFusePid = fork())) {
8236801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        if (execl(kFusePath, kFusePath,
83deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey                "-u", "1023", // AID_MEDIA_RW
84deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey                "-g", "1023", // AID_MEDIA_RW
8566270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey                "-m",
8666270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey                "-w",
8775ae529bf86c33106e6a716ad054c6eea6deabc5Rom Lemarchand                "-G",
88deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey                mRawPath.c_str(),
8981f55c6dc1a14ed68e404fa3a2c244dd343e4990Jeff Sharkey                label.c_str(),
9036801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey                NULL)) {
9136801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            PLOG(ERROR) << "Failed to exec";
92deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey        }
9336801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
94c7b5b570bd05ed3bc921b0c2dc346416a52b4e3eJeff Sharkey        LOG(ERROR) << "FUSE exiting";
95deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey        _exit(1);
96deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey    }
97deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey
98deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey    if (mFusePid == -1) {
999c48498f4529f623650c56d03e63324c8d813032Jeff Sharkey        PLOG(ERROR) << getId() << " failed to fork";
100deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey        return -errno;
101deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey    }
102deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey
10366270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey    while (before == GetDevice(mFuseWrite)) {
10466270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey        LOG(VERBOSE) << "Waiting for FUSE to spin up...";
10566270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey        usleep(50000); // 50ms
10666270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey    }
1071d79d1014e481c92c3f802bbaf174409d191571fDaniel Rosenberg    /* sdcardfs will have exited already. FUSE will still be running */
1081d79d1014e481c92c3f802bbaf174409d191571fDaniel Rosenberg    TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, WNOHANG));
10966270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey
110deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey    return OK;
111deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey}
112deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey
113deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkeystatus_t EmulatedVolume::doUnmount() {
114ea243a3015edc86428167e97a1ab50c85cf409f2Narayan Kamath    // Unmount the storage before we kill the FUSE process. If we kill
115ea243a3015edc86428167e97a1ab50c85cf409f2Narayan Kamath    // the FUSE process first, most file system operations will return
116ea243a3015edc86428167e97a1ab50c85cf409f2Narayan Kamath    // ENOTCONN until the unmount completes. This is an exotic and unusual
117ea243a3015edc86428167e97a1ab50c85cf409f2Narayan Kamath    // error code and might cause broken behaviour in applications.
118ea243a3015edc86428167e97a1ab50c85cf409f2Narayan Kamath    KillProcessesUsingPath(getPath());
119ea243a3015edc86428167e97a1ab50c85cf409f2Narayan Kamath    ForceUnmount(mFuseDefault);
120ea243a3015edc86428167e97a1ab50c85cf409f2Narayan Kamath    ForceUnmount(mFuseRead);
121ea243a3015edc86428167e97a1ab50c85cf409f2Narayan Kamath    ForceUnmount(mFuseWrite);
122ea243a3015edc86428167e97a1ab50c85cf409f2Narayan Kamath
123deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey    if (mFusePid > 0) {
124deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey        kill(mFusePid, SIGTERM);
125deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey        TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0));
126deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey        mFusePid = 0;
127deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey    }
128deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey
12966270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey    rmdir(mFuseDefault.c_str());
13066270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey    rmdir(mFuseRead.c_str());
13166270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey    rmdir(mFuseWrite.c_str());
13266270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey
13366270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey    mFuseDefault.clear();
13466270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey    mFuseRead.clear();
13566270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey    mFuseWrite.clear();
136deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey
137deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey    return OK;
138deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey}
139deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey
140deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey}  // namespace vold
141deb240573754daf36fa8ea10a05240f9f31e7b2cJeff Sharkey}  // namespace android
142