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", "none"};
115     if (std::find(supported_fs.begin(), supported_fs.end(), rec->fs_type) == supported_fs.end()) {
116         LERROR << "unknown fs_type \"" << rec->fs_type << "\" for " << mount_point;
117         return false;
118     }
119 
120     int result = fs_mgr_do_mount_one(*rec, mount_point);
121     if (result == -1 && rec->fs_mgr_flags.formattable) {
122         PERROR << "Failed to mount " << mount_point << "; formatting";
123         bool crypt_footer = rec->is_encryptable() && rec->key_loc == "footer";
124         if (fs_mgr_do_format(*rec, crypt_footer) != 0) {
125             PERROR << "Failed to format " << mount_point;
126             return false;
127         }
128         result = fs_mgr_do_mount_one(*rec, mount_point);
129     }
130 
131     if (result == -1) {
132         PERROR << "Failed to mount " << mount_point;
133         return false;
134     }
135     return true;
136 }
137 
EnsurePathUnmounted(Fstab * fstab,const std::string & path)138 bool EnsurePathUnmounted(Fstab* fstab, const std::string& path) {
139     auto rec = GetEntryForPath(fstab, path);
140     if (rec == nullptr) {
141         LERROR << "unknown volume for path [" << path << "]";
142         return false;
143     }
144     if (rec->fs_type == "ramdisk") {
145         // The ramdisk is always mounted; you can't unmount it.
146         return false;
147     }
148 
149     Fstab mounted_fstab;
150     if (!ReadFstabFromFile("/proc/mounts", &mounted_fstab)) {
151         LERROR << "Failed to scan mounted volumes";
152         return false;
153     }
154 
155     auto mounted = GetMountState(rec->mount_point);
156     if (mounted == MountState::ERROR) {
157         return false;
158     }
159     if (mounted == MountState::NOT_MOUNTED) {
160         return true;
161     }
162 
163     int result = umount(rec->mount_point.c_str());
164     if (result == -1) {
165         PWARNING << "Failed to umount " << rec->mount_point;
166         return false;
167     }
168     return true;
169 }
170 
GetSystemRoot()171 std::string GetSystemRoot() {
172     Fstab fstab;
173     if (!ReadDefaultFstab(&fstab)) {
174         LERROR << "Failed to read default fstab";
175         return "";
176     }
177 
178     auto entry = GetEntryForMountPoint(&fstab, kSystemRoot);
179     if (entry == nullptr) {
180         return "/";
181     }
182 
183     return kSystemRoot;
184 }
185 
LogicalPartitionsMapped()186 bool LogicalPartitionsMapped() {
187     return gDidMapLogicalPartitions;
188 }
189 
190 }  // namespace fs_mgr
191 }  // namespace android
192