1 /*
2 * Copyright (C) 2018 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 "android-base/file.h"
18 #include "fs_mgr/roots.h"
19
20 #include <sys/mount.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23
24 #include <string>
25
26 #include "fs_mgr.h"
27 #include "fs_mgr_dm_linear.h"
28 #include "fs_mgr_priv.h"
29
30 namespace android {
31 namespace fs_mgr {
32
33 static constexpr const char* kSystemRoot = "/system";
34
35 static bool gDidMapLogicalPartitions = false;
36
GetEntryForPath(Fstab * fstab,const std::string & path)37 FstabEntry* GetEntryForPath(Fstab* fstab, const std::string& path) {
38 if (path.empty()) return nullptr;
39 std::string str(path);
40 while (true) {
41 auto entry = GetEntryForMountPoint(fstab, str);
42 if (entry != nullptr) return entry;
43 str = android::base::Dirname(str);
44 if (!str.compare(".") || !str.compare("/")) break;
45 }
46 return nullptr;
47 }
48
GetEntriesForPath(Fstab * fstab,const std::string & path)49 std::vector<FstabEntry*> GetEntriesForPath(Fstab* fstab, const std::string& path) {
50 std::vector<FstabEntry*> entries;
51 if (path.empty()) return entries;
52
53 std::string str(path);
54 while (true) {
55 entries = GetEntriesForMountPoint(fstab, str);
56 if (!entries.empty()) return entries;
57 str = android::base::Dirname(str);
58 if (!str.compare(".") || !str.compare("/")) break;
59 }
60 return entries;
61 }
62
63 enum class MountState {
64 ERROR = -1,
65 NOT_MOUNTED = 0,
66 MOUNTED = 1,
67 };
68
GetMountState(const std::string & mount_point)69 static MountState GetMountState(const std::string& mount_point) {
70 Fstab mounted_fstab;
71 if (!ReadFstabFromFile("/proc/mounts", &mounted_fstab)) {
72 LERROR << "Failed to scan mounted volumes";
73 return MountState::ERROR;
74 }
75
76 auto mv = GetEntryForMountPoint(&mounted_fstab, mount_point);
77 if (mv != nullptr) {
78 return MountState::MOUNTED;
79 }
80 return MountState::NOT_MOUNTED;
81 }
82
TryPathMount(FstabEntry * rec,const std::string & mount_pt)83 bool TryPathMount(FstabEntry* rec, const std::string& mount_pt) {
84 if (rec->fs_type == "ramdisk") {
85 // The ramdisk is always mounted.
86 return true;
87 }
88
89 // If we can't acquire the block device for a logical partition, it likely
90 // was never created. In that case we try to create it.
91 if (rec->fs_mgr_flags.logical && !fs_mgr_update_logical_partition(rec)) {
92 if (gDidMapLogicalPartitions) {
93 LERROR << "Failed to find block device for partition";
94 return false;
95 }
96 std::string super_name = fs_mgr_get_super_partition_name();
97 if (!android::fs_mgr::CreateLogicalPartitions("/dev/block/by-name/" + super_name)) {
98 LERROR << "Failed to create logical partitions";
99 return false;
100 }
101 gDidMapLogicalPartitions = true;
102 if (!fs_mgr_update_logical_partition(rec)) {
103 LERROR << "Failed to find block device for partition";
104 return false;
105 }
106 }
107
108 const std::string mount_point = mount_pt.empty() ? rec->mount_point : mount_pt;
109
110 auto mounted = GetMountState(mount_point);
111 if (mounted == MountState::ERROR) {
112 return false;
113 }
114 if (mounted == MountState::MOUNTED) {
115 return true;
116 }
117
118 static const std::vector<std::string> supported_fs{"ext4", "squashfs", "vfat", "exfat", "f2fs",
119 "erofs", "none"};
120 if (std::find(supported_fs.begin(), supported_fs.end(), rec->fs_type) == supported_fs.end()) {
121 LERROR << "unknown fs_type \"" << rec->fs_type << "\" for " << mount_point;
122 return false;
123 }
124
125 int result = fs_mgr_do_mount_one(*rec, mount_point);
126 if (result == -1 && rec->fs_mgr_flags.formattable) {
127 PERROR << "Failed to mount " << mount_point << "; formatting";
128 if (fs_mgr_do_format(*rec) != 0) {
129 PERROR << "Failed to format " << mount_point;
130 return false;
131 }
132 result = fs_mgr_do_mount_one(*rec, mount_point);
133 }
134
135 if (result == -1) {
136 PERROR << "Failed to mount " << mount_point;
137 return false;
138 }
139 return true;
140 }
141
EnsurePathMounted(Fstab * fstab,const std::string & path,const std::string & mount_point)142 bool EnsurePathMounted(Fstab* fstab, const std::string& path, const std::string& mount_point) {
143 auto entries = GetEntriesForPath(fstab, path);
144 if (entries.empty()) {
145 LERROR << "unknown volume for path [" << path << "]";
146 return false;
147 }
148
149 for (auto entry : entries) {
150 if (TryPathMount(entry, mount_point)) return true;
151 }
152
153 LERROR << "Failed to mount for path [" << path << "]";
154 return false;
155 }
156
EnsurePathUnmounted(Fstab * fstab,const std::string & path)157 bool EnsurePathUnmounted(Fstab* fstab, const std::string& path) {
158 auto rec = GetEntryForPath(fstab, path);
159 if (rec == nullptr) {
160 LERROR << "unknown volume for path [" << path << "]";
161 return false;
162 }
163 if (rec->fs_type == "ramdisk") {
164 // The ramdisk is always mounted; you can't unmount it.
165 return false;
166 }
167
168 Fstab mounted_fstab;
169 if (!ReadFstabFromFile("/proc/mounts", &mounted_fstab)) {
170 LERROR << "Failed to scan mounted volumes";
171 return false;
172 }
173
174 auto mounted = GetMountState(rec->mount_point);
175 if (mounted == MountState::ERROR) {
176 return false;
177 }
178 if (mounted == MountState::NOT_MOUNTED) {
179 return true;
180 }
181
182 int result = umount(rec->mount_point.c_str());
183 if (result == -1) {
184 PWARNING << "Failed to umount " << rec->mount_point;
185 return false;
186 }
187 return true;
188 }
189
GetSystemRoot()190 std::string GetSystemRoot() {
191 Fstab fstab;
192 if (!ReadDefaultFstab(&fstab)) {
193 LERROR << "Failed to read default fstab";
194 return "";
195 }
196
197 auto entry = GetEntryForMountPoint(&fstab, kSystemRoot);
198 if (entry == nullptr) {
199 return "/";
200 }
201
202 return kSystemRoot;
203 }
204
LogicalPartitionsMapped()205 bool LogicalPartitionsMapped() {
206 return gDidMapLogicalPartitions;
207 }
208
209 } // namespace fs_mgr
210 } // namespace android
211