blob: ded6565b1985cd5f3e3b532c4d85d034c5e14e9d [file] [log] [blame]
Tom Marshall292bd232019-01-04 14:37:31 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 * Copyright (C) 2019 The LineageOS Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include <blkid/blkid.h>
19#include <dirent.h>
20#include <fcntl.h>
21#include <fs_mgr.h>
22#include <sys/stat.h>
23#include <sys/sysmacros.h>
24#include <sys/types.h>
25
26#define LOG_TAG "VolumeManager"
27
28#include <android-base/logging.h>
29#include <cutils/properties.h>
30
31#include <sysutils/NetlinkEvent.h>
32
33#include <volume_manager/VolumeManager.h>
34#include <fstab/fstab.h>
35#include "Disk.h"
36#include "DiskPartition.h"
37#include "EmulatedVolume.h"
38#include "VolumeBase.h"
39#include "NetlinkManager.h"
40
41#include "sehandle.h"
42
43struct selabel_handle* sehandle;
44
45using android::fs_mgr::Fstab;
46using android::fs_mgr::FstabEntry;
47
48static const unsigned int kMajorBlockMmc = 179;
49static const unsigned int kMajorBlockExperimentalMin = 240;
50static const unsigned int kMajorBlockExperimentalMax = 254;
51
52namespace android {
53namespace volmgr {
54
55static void do_coldboot(DIR* d, int lvl) {
56 struct dirent* de;
57 int dfd, fd;
58
59 dfd = dirfd(d);
60
61 fd = openat(dfd, "uevent", O_WRONLY | O_CLOEXEC);
62 if (fd >= 0) {
63 write(fd, "add\n", 4);
64 close(fd);
65 }
66
67 while ((de = readdir(d))) {
68 DIR* d2;
69
70 if (de->d_name[0] == '.') continue;
71
72 if (de->d_type != DT_DIR && lvl > 0) continue;
73
74 fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
75 if (fd < 0) continue;
76
77 d2 = fdopendir(fd);
78 if (d2 == 0)
79 close(fd);
80 else {
81 do_coldboot(d2, lvl + 1);
82 closedir(d2);
83 }
84 }
85}
86
87static void coldboot(const char* path) {
88 DIR* d = opendir(path);
89 if (d) {
90 do_coldboot(d, 0);
91 closedir(d);
92 }
93}
94
95static int process_config(VolumeManager* vm, FstabEntry* data_recp) {
96 Fstab fstab;
97 if (!ReadDefaultFstab(&fstab)) {
98 PLOG(ERROR) << "Failed to open default fstab";
99 return -1;
100 }
101
102 /* Loop through entries looking for ones that vold manages */
103 for (int i = 0; i < fstab.size(); i++) {
104 if (fstab[i].fs_mgr_flags.vold_managed) {
105 std::string sysPattern(fstab[i].blk_device);
106 std::string fstype = fstab[i].fs_type;
107 std::string mntopts = fstab[i].fs_options;
108 std::string nickname = fstab[i].label;
109 int partnum = fstab[i].partnum;
110 int flags = 0;
111
112 if (fstab[i].is_encryptable()) {
113 flags |= android::volmgr::Disk::Flags::kAdoptable;
114 }
115 if (fstab[i].fs_mgr_flags.no_emulated_sd ||
116 property_get_bool("vold.debug.default_primary", false)) {
117 flags |= android::volmgr::Disk::Flags::kDefaultPrimary;
118 }
119 if (fstab[i].fs_mgr_flags.nonremovable) {
120 flags |= android::volmgr::Disk::Flags::kNonRemovable;
121 }
122
123 vm->addDiskSource(new VolumeManager::DiskSource(sysPattern, nickname, partnum, flags,
124 fstype, mntopts));
125 } else {
126 if (data_recp->fs_type.empty() && fstab[i].mount_point == "/data") {
127 char* detected_fs_type =
128 blkid_get_tag_value(nullptr, "TYPE", fstab[i].blk_device.c_str());
129 if (!detected_fs_type || fstab[i].fs_type == detected_fs_type) {
130 *data_recp = fstab[i];
131 }
132 }
133 }
134 }
135 return 0;
136}
137
138VolumeInfo::VolumeInfo(const VolumeBase* vol)
Tom Marshall0057c5f2019-07-24 21:12:07 +0200139 : mId(vol->getId()), mLabel(vol->getPartLabel()), mPath(vol->getPath()), mMountable(vol->isMountable()) {
Tom Marshall292bd232019-01-04 14:37:31 -0800140 // Empty
141}
142
143VolumeManager* VolumeManager::sInstance = nullptr;
144
145VolumeManager* VolumeManager::Instance(void) {
146 if (!sInstance) {
147 sInstance = new VolumeManager();
148 }
149 return sInstance;
150}
151
152VolumeManager::VolumeManager(void)
153 : mWatcher(nullptr), mNetlinkManager(NetlinkManager::Instance()), mInternalEmulated(nullptr) {
154 // Empty
155}
156
157VolumeManager::~VolumeManager(void) {
158 stop();
159}
160
161bool VolumeManager::start(VolumeWatcher* watcher) {
162 setenv("BLKID_FILE", "/tmp/vold_blkid.tab", 1);
163
164 sehandle = selinux_android_file_context_handle();
165 if (sehandle) {
166 selinux_android_set_sehandle(sehandle);
167 }
168
169 mkdir("/dev/block/volmgr", 0755);
170
171 mWatcher = watcher;
172
173 FstabEntry data_rec;
174 if (process_config(this, &data_rec) != 0) {
175 LOG(ERROR) << "Error reading configuration... continuing anyway";
176 }
177
178 if (!data_rec.fs_type.empty()) {
179 mInternalEmulated = new EmulatedVolume(&data_rec, "media/0");
180 mInternalEmulated->create();
181 }
182
183 if (!mNetlinkManager->start()) {
184 LOG(ERROR) << "Unable to start NetlinkManager";
185 return false;
186 }
187
188 coldboot("/sys/block");
189
190 unmountAll();
191
192 LOG(INFO) << "VolumeManager initialized";
193 return true;
194}
195
196void VolumeManager::stop(void) {
197 for (auto& disk : mDisks) {
198 disk->destroy();
199 delete disk;
200 }
201 mDisks.clear();
202 for (auto& source : mDiskSources) {
203 delete source;
204 }
205 mDiskSources.clear();
206
207 mNetlinkManager->stop();
208 mWatcher = nullptr;
209}
210
211bool VolumeManager::reset(void) {
212 return false;
213}
214
215bool VolumeManager::unmountAll(void) {
216 std::lock_guard<std::mutex> lock(mLock);
217
218 if (mInternalEmulated) {
219 mInternalEmulated->unmount();
220 }
221
222 for (auto& disk : mDisks) {
223 disk->unmountAll();
224 }
225
226 return true;
227}
228
229void VolumeManager::getVolumeInfo(std::vector<VolumeInfo>& info) {
230 std::lock_guard<std::mutex> lock(mLock);
231
232 info.clear();
233 if (mInternalEmulated) {
234 info.push_back(VolumeInfo(mInternalEmulated));
235 }
236 for (const auto& disk : mDisks) {
237 disk->getVolumeInfo(info);
238 }
239}
240
241VolumeBase* VolumeManager::findVolume(const std::string& id) {
242 if (mInternalEmulated && mInternalEmulated->getId() == id) {
243 return mInternalEmulated;
244 }
245 for (const auto& disk : mDisks) {
246 auto vol = disk->findVolume(id);
247 if (vol != nullptr) {
248 return vol.get();
249 }
250 }
251 return nullptr;
252}
253
254bool VolumeManager::volumeMount(const std::string& id) {
255 std::lock_guard<std::mutex> lock(mLock);
256 auto vol = findVolume(id);
257 if (!vol) {
258 return false;
259 }
260 status_t res = vol->mount();
261 return (res == OK);
262}
263
264bool VolumeManager::volumeUnmount(const std::string& id, bool detach /* = false */) {
265 std::lock_guard<std::mutex> lock(mLock);
266 auto vol = findVolume(id);
267 if (!vol) {
268 return false;
269 }
270 status_t res = vol->unmount(detach);
271 return (res == OK);
272}
273
274void VolumeManager::addDiskSource(DiskSource* source) {
275 std::lock_guard<std::mutex> lock(mLock);
276
277 mDiskSources.push_back(source);
278}
279
280void VolumeManager::handleBlockEvent(NetlinkEvent* evt) {
281 std::lock_guard<std::mutex> lock(mLock);
282
283 const char* param;
284 param = evt->findParam("DEVTYPE");
285 std::string devType(param ? param : "");
286 if (devType != "disk") {
287 return;
288 }
289 param = evt->findParam("DEVPATH");
290 std::string eventPath(param ? param : "");
291
292 int major = atoi(evt->findParam("MAJOR"));
293 int minor = atoi(evt->findParam("MINOR"));
294 dev_t device = makedev(major, minor);
295
296 switch (evt->getAction()) {
297 case NetlinkEvent::Action::kAdd: {
298 for (const auto& source : mDiskSources) {
299 if (source->matches(eventPath)) {
300 // For now, assume that MMC, virtio-blk (the latter is
301 // emulator-specific; see Disk.cpp for details) and UFS card
302 // devices are SD, and that everything else is USB
303 int flags = source->getFlags();
304 if (major == kMajorBlockMmc || (eventPath.find("ufs") != std::string::npos) ||
305 (IsRunningInEmulator() && major >= (int)kMajorBlockExperimentalMin &&
306 major <= (int)kMajorBlockExperimentalMax)) {
307 flags |= Disk::Flags::kSd;
308 } else {
309 flags |= Disk::Flags::kUsb;
310 }
311
312 Disk* disk = (source->getPartNum() == -1)
313 ? new Disk(eventPath, device, source->getNickname(), flags)
314 : new DiskPartition(eventPath, device, source->getNickname(),
315 flags, source->getPartNum(),
316 source->getFsType(), source->getMntOpts());
317 disk->create();
318 mDisks.push_back(disk);
319 break;
320 }
321 }
322 break;
323 }
324 case NetlinkEvent::Action::kChange: {
325 LOG(DEBUG) << "Disk at " << major << ":" << minor << " changed";
326 for (const auto& disk : mDisks) {
327 if (disk->getDevice() == device) {
328 disk->readMetadata();
329 disk->readPartitions();
330 }
331 }
332 break;
333 }
334 case NetlinkEvent::Action::kRemove: {
335 auto i = mDisks.begin();
336 while (i != mDisks.end()) {
337 if ((*i)->getDevice() == device) {
338 (*i)->destroy();
339 i = mDisks.erase(i);
340 } else {
341 ++i;
342 }
343 }
344 break;
345 }
346 default: {
347 LOG(WARNING) << "Unexpected block event action " << (int)evt->getAction();
348 break;
349 }
350 }
351}
352
353void VolumeManager::notifyEvent(int code) {
354 std::vector<std::string> argv;
355 notifyEvent(code, argv);
356}
357
358void VolumeManager::notifyEvent(int code, const std::string& arg) {
359 std::vector<std::string> argv;
360 argv.push_back(arg);
361 notifyEvent(code, argv);
362}
363
364void VolumeManager::notifyEvent(int code, const std::vector<std::string>& argv) {
365 mWatcher->handleEvent(code, argv);
366}
367
368} // namespace volmgr
369} // namespace android