1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "fs_manager/mount.h"
17 #include <cerrno>
18 #include <fcntl.h>
19 #include <string>
20 #include <sys/mount.h>
21 #include <sys/stat.h>
22 #include <sys/wait.h>
23 #include <unistd.h>
24 #include <vector>
25 #include <linux/fs.h>
26 #include "log/log.h"
27 #include "utils.h"
28
29 namespace Updater {
30 using Updater::Utils::SplitString;
31 static std::string g_defaultUpdaterFstab = "";
32 static Fstab *g_fstab = nullptr;
33 static const std::string PARTITION_PATH = "/dev/block/by-name";
34
GetFstabFile()35 static std::string GetFstabFile()
36 {
37 /* check vendor fstab files from specific directory */
38 std::vector<const std::string> specificFstabFiles = {"/vendor/etc/fstab.updater"};
39 for (auto& fstabFile : specificFstabFiles) {
40 if (access(fstabFile.c_str(), F_OK) == 0) {
41 return fstabFile;
42 }
43 }
44 return "";
45 }
46
GetMountStatusForPath(const std::string & path)47 MountStatus GetMountStatusForPath(const std::string &path)
48 {
49 FstabItem *item = FindFstabItemForPath(*g_fstab, path.c_str());
50 if (item == nullptr) {
51 return MountStatus::MOUNT_ERROR;
52 }
53 return GetMountStatusForMountPoint(item->mountPoint);
54 }
55
LoadFstab()56 void LoadFstab()
57 {
58 std::string fstabFile = g_defaultUpdaterFstab;
59 if (fstabFile.empty()) {
60 fstabFile = GetFstabFile();
61 if (fstabFile.empty()) {
62 fstabFile = "/etc/fstab.updater";
63 }
64 }
65 // Clear fstab before read fstab file.
66 if ((g_fstab = ReadFstabFromFile(fstabFile.c_str(), false)) == nullptr) {
67 LOG(WARNING) << "Read " << fstabFile << " failed";
68 return;
69 }
70
71 LOG(DEBUG) << "Updater filesystem config info:";
72 for (FstabItem *item = g_fstab->head; item != nullptr; item = item->next) {
73 LOG(DEBUG) << "\tDevice: " << item->deviceName;
74 LOG(DEBUG) << "\tMount point : " << item->mountPoint;
75 LOG(DEBUG) << "\tFs type : " << item->fsType;
76 LOG(DEBUG) << "\tMount options: " << item->mountOptions;
77 }
78 }
79
LoadSpecificFstab(const std::string & fstabName)80 void LoadSpecificFstab(const std::string &fstabName)
81 {
82 g_defaultUpdaterFstab = fstabName;
83 LoadFstab();
84 g_defaultUpdaterFstab = "";
85 }
86
UmountForPath(const std::string & path)87 int UmountForPath(const std::string& path)
88 {
89 FstabItem *item = FindFstabItemForPath(*g_fstab, path.c_str());
90 if (item == nullptr) {
91 LOG(ERROR) << "Cannot find fstab item for " << path << " to umount.";
92 return -1;
93 }
94
95 LOG(DEBUG) << "Umount for path " << path;
96 MountStatus rc = GetMountStatusForMountPoint(item->mountPoint);
97 if (rc == MOUNT_ERROR) {
98 return -1;
99 } else if (rc == MOUNT_UMOUNTED) {
100 return 0;
101 } else {
102 int ret = umount(item->mountPoint);
103 if (ret == -1) {
104 LOG(ERROR) << "Umount " << item->mountPoint << "failed: " << errno;
105 return -1;
106 }
107 }
108 return 0;
109 }
110
MountForPath(const std::string & path)111 int MountForPath(const std::string &path)
112 {
113 FstabItem *item = FindFstabItemForPath(*g_fstab, path.c_str());
114 int ret = -1;
115 if (item == nullptr) {
116 LOG(ERROR) << "Cannot find fstab item for " << path << " to mount.";
117 return -1;
118 }
119
120 LOG(DEBUG) << "Mount for path " << path;
121 MountStatus rc = GetMountStatusForMountPoint(item->mountPoint);
122 if (rc == MountStatus::MOUNT_ERROR) {
123 ret = -1;
124 } else if (rc == MountStatus::MOUNT_MOUNTED) {
125 LOG(INFO) << path << " already mounted";
126 ret = 0;
127 } else {
128 ret = MountOneItem(item);
129 }
130 return ret;
131 }
132
ErasePartition(const std::string & devPath)133 void ErasePartition(const std::string &devPath)
134 {
135 std::string realPath {};
136 if (!Utils::PathToRealPath(devPath, realPath)) {
137 LOG(ERROR) << "realpath failed:" << devPath;
138 return;
139 }
140 int fd = open(realPath.c_str(), O_RDWR | O_LARGEFILE);
141 if (fd == -1) {
142 LOG(ERROR) << "open failed:" << realPath;
143 return;
144 }
145
146 uint64_t size = 0;
147 int ret = ioctl(fd, BLKGETSIZE64, &size);
148 if (ret < 0) {
149 LOG(ERROR) << "get partition size failed:" << size;
150 close(fd);
151 return;
152 }
153
154 LOG(INFO) << "erase partition size:" << size;
155
156 uint64_t range[] { 0, size };
157 ret = ioctl(fd, BLKDISCARD, &range);
158 if (ret < 0) {
159 LOG(ERROR) << "erase partition failed";
160 }
161 close(fd);
162
163 return;
164 }
165
FormatPartition(const std::string & path,bool isZeroErase)166 int FormatPartition(const std::string &path, bool isZeroErase)
167 {
168 FstabItem *item = FindFstabItemForPath(*g_fstab, path.c_str());
169 if (item == nullptr) {
170 LOG(ERROR) << "Cannot find fstab item for " << path << " to format.";
171 return -1;
172 }
173
174 if (strcmp(item->mountPoint, "/") == 0) {
175 /* Can not format root */
176 return 0;
177 }
178
179 if (!IsSupportedFilesystem(item->fsType)) {
180 LOG(ERROR) << "Try to format " << item->mountPoint << " with unsupported file system type: " << item->fsType;
181 return -1;
182 }
183
184 // Umount first
185 if (UmountForPath(path) != 0) {
186 return -1;
187 }
188
189 if (isZeroErase) {
190 ErasePartition(item->deviceName);
191 }
192
193 int ret = DoFormat(item->deviceName, item->fsType);
194 if (ret != 0) {
195 LOG(ERROR) << "Format " << path << " failed";
196 }
197 return ((ret != 0) ? -1 : 0);
198 }
199
SetupPartitions(PackageUpdateMode mode)200 int SetupPartitions(PackageUpdateMode mode)
201 {
202 if (!Utils::IsUpdaterMode()) {
203 LOG(ERROR) << "live update mode";
204 return 0;
205 }
206
207 if (g_fstab == NULL || g_fstab->head == NULL) {
208 LOG(ERROR) << "Fstab is invalid";
209 return -1;
210 }
211 for (const FstabItem *item = g_fstab->head; item != nullptr; item = item->next) {
212 std::string mountPoint(item->mountPoint);
213 std::string fsType(item->fsType);
214 if (mountPoint == "/" || mountPoint == "/tmp" || fsType == "none" ||
215 mountPoint == "/sdcard") {
216 continue;
217 }
218
219 if (mountPoint == "/data" && mode != SDCARD_UPDATE) {
220 if (MountForPath(mountPoint) != 0) {
221 LOG(ERROR) << "Expected partition " << mountPoint << " is not mounted.";
222 return -1;
223 }
224 continue;
225 }
226 if (UmountForPath(mountPoint) != 0) {
227 LOG(ERROR) << "Umount " << mountPoint << " failed";
228 return -1;
229 }
230 }
231 return 0;
232 }
233
GetBlockDeviceByMountPoint(const std::string & mountPoint)234 const std::string GetBlockDeviceByMountPoint(const std::string &mountPoint)
235 {
236 if (mountPoint.empty()) {
237 LOG(ERROR) << "mountPoint empty error.";
238 return "";
239 }
240 std::string blockDevice = PARTITION_PATH + mountPoint;
241 if (mountPoint[0] != '/') {
242 blockDevice = PARTITION_PATH + "/" + mountPoint;
243 }
244 if (g_fstab != nullptr) {
245 FstabItem *item = FindFstabItemForMountPoint(*g_fstab, mountPoint.c_str());
246 if (item != NULL) {
247 blockDevice = item->deviceName;
248 }
249 }
250 return blockDevice;
251 }
252 } // updater
253