blob: 255a6bc5e15367636e8860116b284a6f4c079135 [file] [log] [blame]
Jeff Sharkeydeb24052015-03-02 21:01:40 -08001/*
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#define LOG_TAG "Vold"
18
19#include "Fat.h"
20#include "PublicVolume.h"
21#include "Utils.h"
22
Dan Albertae9e8902015-03-16 10:35:17 -070023#include <base/stringprintf.h>
Jeff Sharkeydeb24052015-03-02 21:01:40 -080024#include <cutils/fs.h>
25#include <cutils/log.h>
Jeff Sharkeydeb24052015-03-02 21:01:40 -080026#include <private/android_filesystem_config.h>
27
28#include <fcntl.h>
29#include <stdlib.h>
30#include <sys/mount.h>
31#include <sys/stat.h>
32#include <sys/types.h>
33#include <sys/wait.h>
34
Dan Albertae9e8902015-03-16 10:35:17 -070035using android::base::StringPrintf;
36
Jeff Sharkeydeb24052015-03-02 21:01:40 -080037namespace android {
38namespace vold {
39
40static const char* kBlkidPath = "/system/bin/blkid";
41static const char* kFusePath = "/system/bin/sdcard";
42
43static const char* kUserMountPath = "/mnt/user";
44
45PublicVolume::PublicVolume(dev_t device) :
46 VolumeBase(VolumeType::kPublic), mDevice(device), mFusePid(0), mPrimary(false) {
47 mId = StringPrintf("public:%ud:%ud", major(device), minor(device));
48 mDevPath = StringPrintf("/dev/block/vold/%ud:%ud", major(device), minor(device));
49 mRawPath = StringPrintf("/mnt/media_rw/public_raw_%ud:%ud", major(device), minor(device));
50 mFusePath = StringPrintf("/mnt/media_rw/public_fuse_%ud:%ud", major(device), minor(device));
51
52 CreateDeviceNode(mDevPath, device);
53}
54
55PublicVolume::~PublicVolume() {
56 DestroyDeviceNode(mDevPath);
57}
58
59status_t PublicVolume::readMetadata() {
60 mFsUuid = "";
61 mFsLabel = "";
62
63 std::string path(StringPrintf("%s -c /dev/null %s", kBlkidPath, mDevPath.c_str()));
64 FILE* fp = popen(path.c_str(), "r");
65 if (!fp) {
66 ALOGE("Failed to run %s: %s", path.c_str(), strerror(errno));
67 return -errno;
68 }
69
70 char line[1024];
71 char value[128];
72 if (fgets(line, sizeof(line), fp) != nullptr) {
73 ALOGD("blkid identified as %s", line);
74
75 char* start = strstr(line, "UUID=");
76 if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
77 mFsUuid = value;
78 }
79
80 start = strstr(line, "LABEL=");
81 if (start != nullptr && sscanf(start + 6, "\"%127[^\"]\"", value) == 1) {
82 mFsLabel = value;
83 }
84 } else {
85 ALOGW("blkid failed to identify %s", mDevPath.c_str());
86 return -ENODATA;
87 }
88
89 pclose(fp);
90
91 // TODO: broadcast ident to framework
92 return OK;
93}
94
95status_t PublicVolume::initAsecStage() {
96 std::string legacyPath(mRawPath + "/android_secure");
97 std::string securePath(mRawPath + "/.android_secure");
98
99 // Recover legacy secure path
100 if (!access(legacyPath.c_str(), R_OK | X_OK)
101 && access(securePath.c_str(), R_OK | X_OK)) {
102 if (rename(legacyPath.c_str(), securePath.c_str())) {
103 SLOGE("Failed to rename legacy ASEC dir: %s", strerror(errno));
104 }
105 }
106
107 if (fs_prepare_dir(securePath.c_str(), 0770, AID_MEDIA_RW, AID_MEDIA_RW) != 0) {
108 SLOGW("fs_prepare_dir failed: %s", strerror(errno));
109 return -errno;
110 }
111
112 return OK;
113}
114
115status_t PublicVolume::doMount() {
116 if (Fat::check(mDevPath.c_str())) {
117 SLOGE("Failed filesystem check; not mounting");
118 return -EIO;
119 }
120
121 if (fs_prepare_dir(mRawPath.c_str(), 0770, AID_MEDIA_RW, AID_MEDIA_RW)) {
122 SLOGE("Failed to create mount point %s: %s", mRawPath.c_str(), strerror(errno));
123 return -errno;
124 }
125 if (fs_prepare_dir(mFusePath.c_str(), 0770, AID_MEDIA_RW, AID_MEDIA_RW)) {
126 SLOGE("Failed to create mount point %s: %s", mFusePath.c_str(), strerror(errno));
127 return -errno;
128 }
129
130 if (Fat::doMount(mDevPath.c_str(), mRawPath.c_str(), false, false, false,
131 AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) {
132 SLOGE("Failed to mount %s: %s", mDevPath.c_str(), strerror(errno));
133 return -EIO;
134 }
135
136 if (!(mFusePid = fork())) {
137 if (mPrimary) {
138 if (execl(kFusePath,
139 "-u", "1023", // AID_MEDIA_RW
140 "-g", "1023", // AID_MEDIA_RW
141 "-d",
142 mRawPath.c_str(),
143 mFusePath.c_str())) {
144 SLOGE("Failed to exec: %s", strerror(errno));
145 }
146 } else {
147 if (execl(kFusePath,
148 "-u", "1023", // AID_MEDIA_RW
149 "-g", "1023", // AID_MEDIA_RW
150 "-w", "1023", // AID_MEDIA_RW
151 "-d",
152 mRawPath.c_str(),
153 mFusePath.c_str())) {
154 SLOGE("Failed to exec: %s", strerror(errno));
155 }
156 }
157
158 _exit(1);
159 }
160
161 if (mFusePid == -1) {
162 SLOGE("Failed to fork: %s", strerror(errno));
163 return -errno;
164 }
165
166 return OK;
167}
168
169status_t PublicVolume::doUnmount() {
170 if (mFusePid > 0) {
171 kill(mFusePid, SIGTERM);
172 TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0));
173 mFusePid = 0;
174 }
175
176 ForceUnmount(mFusePath);
177 ForceUnmount(mRawPath);
178
179 TEMP_FAILURE_RETRY(unlink(mRawPath.c_str()));
180 TEMP_FAILURE_RETRY(unlink(mFusePath.c_str()));
181
182 return OK;
183}
184
185status_t PublicVolume::doFormat() {
186 if (Fat::format(mDevPath.c_str(), 0, true)) {
187 SLOGE("Failed to format: %s", strerror(errno));
188 return -errno;
189 }
190 return OK;
191}
192
193status_t PublicVolume::bindUser(userid_t user) {
194 return bindUserInternal(user, true);
195}
196
197status_t PublicVolume::unbindUser(userid_t user) {
198 return bindUserInternal(user, false);
199}
200
201status_t PublicVolume::bindUserInternal(userid_t user, bool bind) {
202 if (mPrimary) {
203 if (user == 0) {
204 std::string path(StringPrintf("%s/%ud/primary", kUserMountPath, user));
205 if (bind) {
206 mountBind(mFusePath, path);
207 } else {
208 unmountBind(path);
209 }
210 } else {
211 // Public volumes are only visible to owner when primary
212 // storage, so we don't mount for secondary users.
213 }
214 } else {
215 std::string path(StringPrintf("%s/%ud/public_%ud:%ud", kUserMountPath, user,
216 major(mDevice), minor(mDevice)));
217 if (bind) {
218 mountBind(mFusePath, path);
219 } else {
220 unmountBind(path);
221 }
222
223 if (user != 0) {
224 // To prevent information leakage between users, only owner
225 // has access to the Android directory
226 path += "/Android";
227 if (bind) {
228 if (::mount("tmpfs", path.c_str(), "tmpfs", MS_NOSUID, "mode=0000")) {
229 SLOGE("Failed to protect secondary path %s: %s",
230 path.c_str(), strerror(errno));
231 return -errno;
232 }
233 } else {
234 ForceUnmount(path);
235 }
236 }
237 }
238
239 return OK;
240}
241
242void PublicVolume::setPrimary(bool primary) {
243 if (getState() != VolumeState::kUnmounted) {
244 SLOGE("Primary state change requires %s to be unmounted", getId().c_str());
245 return;
246 }
247
248 mPrimary = primary;
249}
250
251} // namespace vold
252} // namespace android