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