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 #include <cerrno>
16 #include <cstring>
17 #include <linux/blkpg.h>
18 #include <linux/fs.h>
19 #include <libgen.h>
20 #include <string>
21 #include <sys/ioctl.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include "fs_manager/cmp_partition.h"
25 #include "fs_manager/mount.h"
26 #include "fs_manager/partitions.h"
27 #include "log/log.h"
28 #include "misc_info/misc_info.h"
29 #include "partition_const.h"
30 #include "scope_guard.h"
31 #include "securec.h"
32
33 namespace Updater {
34 namespace {
35 constexpr const char *USERDATA_PARTNAME = "userdata";
36 constexpr const char *UPDATER_PARTNAME = "updater";
37 }
38
BlkpgPartCommand(const Partition & part,struct blkpg_partition & pg,int op)39 static int BlkpgPartCommand(const Partition &part, struct blkpg_partition &pg, int op)
40 {
41 struct blkpg_ioctl_arg args {};
42 args.op = op;
43 args.flags = 0;
44 args.datalen = static_cast<int>(sizeof(struct blkpg_partition));
45 args.data = static_cast<void *>(&pg);
46
47 int ret = 0;
48 #ifndef UPDATER_UT
49 ret = ioctl(part.partfd, BLKPG, &args);
50 #endif
51 if (ret < 0) {
52 LOG(ERROR) << "ioctl of partition " << part.partName << " with operation " << op << " failed";
53 }
54 return ret;
55 }
56
DoUmountDiskPartition(const Partition & part)57 static int DoUmountDiskPartition(const Partition &part)
58 {
59 std::string partName = std::string("/") + part.partName;
60 int ret = UmountForPath(partName);
61 if (ret == -1) {
62 LOG(ERROR) << "Umount " << partName << " failed: " << errno;
63 return 0;
64 }
65 return 1;
66 }
67
DoFsync(const BlockDevice & dev)68 static void DoFsync(const BlockDevice &dev)
69 {
70 BlockSpecific* bs = BLOCK_SPECIFIC(&dev);
71 int status;
72
73 while (true) {
74 status = fsync (bs->fd);
75 if (status >= 0) {
76 break;
77 }
78 }
79 }
80
BlockSync(const Disk & disk)81 static int BlockSync(const Disk &disk)
82 {
83 if (disk.dev->readOnly) {
84 return 0;
85 }
86 DoFsync(*(disk.dev));
87 return 1;
88 }
89
BlkpgRemovePartition(const Partition & part)90 static int BlkpgRemovePartition(const Partition &part)
91 {
92 struct blkpg_partition blkPart {};
93 if (memset_s(&blkPart, sizeof(blkPart), 0, sizeof(blkPart)) != EOK) {
94 return -1;
95 }
96 blkPart.pno = part.partNum;
97 return BlkpgPartCommand(part, blkPart, BLKPG_DEL_PARTITION);
98 }
99
BlockDiskOpen(Disk & disk)100 static int BlockDiskOpen(Disk &disk)
101 {
102 disk.dev->fd = open(disk.dev->devPath.c_str(), RW_MODE);
103 if (disk.dev->fd < 0) {
104 LOG(WARNING) << "open fail: " << disk.dev->devPath << errno;
105 }
106 return disk.dev->fd;
107 }
108
BlockDiskClose(Disk & disk)109 static void BlockDiskClose(Disk &disk)
110 {
111 if (disk.dev != nullptr) {
112 if (disk.dev->fd > 0) {
113 close(disk.dev->fd);
114 disk.dev->fd = -1;
115 }
116 }
117 }
118
DoRmPartition(const Disk & disk,int partn)119 static bool DoRmPartition(const Disk &disk, int partn)
120 {
121 Partition *part = nullptr;
122 part = GetPartition(disk, partn);
123 if (part == nullptr) {
124 LOG(ERROR) << "Cannot get partition info for partition number: " << partn;
125 return false;
126 }
127
128 if (disk.dev->fd < 0) {
129 return false;
130 }
131 part->partfd = disk.dev->fd;
132 int ret = BlkpgRemovePartition(*part);
133 part->partfd = -1;
134 if (ret < 0) {
135 LOG(ERROR) << "Delete part failed";
136 return false;
137 }
138 return true;
139 }
140
BlkpgAddPartition(Partition & part)141 static int BlkpgAddPartition(Partition &part)
142 {
143 struct blkpg_partition blkPart {};
144 if (memset_s(&blkPart, sizeof(blkPart), 0, sizeof(blkPart)) != EOK) {
145 return 0;
146 }
147 blkPart.start = static_cast<long long>(part.start * SECTOR_SIZE_DEFAULT);
148 LOG(INFO) << "blkPart.start " << blkPart.start;
149 blkPart.length = static_cast<long long>(part.length * SECTOR_SIZE_DEFAULT);
150 LOG(INFO) << "blkPart.length " << blkPart.length;
151 blkPart.pno = part.partNum;
152 LOG(INFO) << "blkPart.pno " << blkPart.pno;
153 if (strncpy_s(blkPart.devname, BLKPG_DEVNAMELTH, part.devName.c_str(), part.devName.size()) != EOK) {
154 return 0;
155 }
156 LOG(INFO) << "blkPart.devname " << blkPart.devname;
157 if (strncpy_s(blkPart.volname, BLKPG_VOLNAMELTH, part.partName.c_str(), part.partName.size()) != EOK) {
158 return 0;
159 }
160 LOG(INFO) << "blkPart.volname " << blkPart.volname;
161 if (BlkpgPartCommand(part, blkPart, BLKPG_ADD_PARTITION) < 0) {
162 return 0;
163 }
164 return 1;
165 }
166
DoAddPartition(const Disk & disk,Partition & part)167 static bool DoAddPartition(const Disk &disk, Partition &part)
168 {
169 if (disk.dev->fd < 0) {
170 return false;
171 }
172
173 part.partfd = disk.dev->fd;
174 int ret = BlkpgAddPartition(part);
175 part.partfd = -1;
176 if (ret == 0) {
177 LOG(ERROR) << "Add partition failed";
178 return false;
179 }
180 return true;
181 }
182
DestroyDiskPartitions(Disk & disk)183 static void DestroyDiskPartitions(Disk &disk)
184 {
185 if (!disk.partList.empty()) {
186 for (auto& p : disk.partList) {
187 if (p != nullptr) {
188 free(p);
189 }
190 }
191 }
192 disk.partList.clear();
193 }
194
DestroyDiskDevices(const Disk & disk)195 static void DestroyDiskDevices(const Disk &disk)
196 {
197 if (disk.dev != nullptr) {
198 if (disk.dev->specific != nullptr) {
199 free(disk.dev->specific);
200 }
201 free(disk.dev);
202 }
203 }
204
WriteMiscMsgWithOffset(const std::string & msg,int32_t offset)205 static bool WriteMiscMsgWithOffset(const std::string &msg, int32_t offset)
206 {
207 const std::string miscDevPath = GetBlockDeviceByMountPoint("/misc");
208 char realPath[PATH_MAX] = {0};
209 if (realpath(miscDevPath.c_str(), realPath) == nullptr) {
210 LOG(ERROR) << "realPath is NULL";
211 return false;
212 }
213 FILE *fp = fopen(realPath, "rb+");
214 if (fp == nullptr) {
215 LOG(ERROR) << "fopen error " << errno;
216 return false;
217 }
218
219 ON_SCOPE_EXIT(flosefp) {
220 fclose(fp);
221 };
222
223 if (fseek(fp, offset, SEEK_SET) != 0) {
224 LOG(ERROR) << "fseek error";
225 return false;
226 }
227
228 if (fwrite(msg.c_str(), msg.length() + 1, 1, fp) < 0) {
229 LOG(ERROR) << "fwrite error " << errno;
230 return false;
231 }
232
233 int fd = fileno(fp);
234 fsync(fd);
235 return true;
236 }
237
WriteDiskPartitionToMisc(PartitonList & nlist)238 static bool WriteDiskPartitionToMisc(PartitonList &nlist)
239 {
240 if (nlist.empty()) {
241 return false;
242 }
243 char blkdevparts[MISC_RECORD_UPDATE_PARTITIONS_SIZE] = "mmcblk0:";
244 std::sort(nlist.begin(), nlist.end(), [](const struct Partition *a, const struct Partition *b) {
245 return (a->start < b->start);
246 }); // Sort in ascending order
247 char tmp[SMALL_BUFFER_SIZE] = {0};
248 size_t size = 0;
249 for (auto& p : nlist) {
250 if (memset_s(tmp, sizeof(tmp), 0, sizeof(tmp)) != EOK) {
251 return false;
252 }
253 if (p->partName == "userdata") {
254 if (snprintf_s(tmp, sizeof(tmp), sizeof(tmp) - 1, "-(%s),",
255 p->partName.c_str()) == -1) {
256 return false;
257 }
258 } else {
259 size = static_cast<size_t>(p->length * SECTOR_SIZE_DEFAULT / DEFAULT_SIZE_1MB);
260 if (snprintf_s(tmp, sizeof(tmp), sizeof(tmp) - 1, "%luM(%s),",
261 size, p->partName.c_str()) == -1) {
262 return false;
263 }
264 }
265 if (strncat_s(blkdevparts, MISC_RECORD_UPDATE_PARTITIONS_SIZE - 1, tmp, strlen(tmp)) != EOK) {
266 LOG(ERROR) << "Block device name overflow";
267 return false;
268 }
269 }
270
271 blkdevparts[strlen(blkdevparts) - 1] = '\0';
272 LOG(INFO) << "blkdevparts is " << blkdevparts;
273
274 return WriteMiscMsgWithOffset(std::string(blkdevparts), MISC_RECORD_UPDATE_PARTITIONS_OFFSET);
275 }
276
AddPartitions(const Disk & disk,const PartitonList & ulist,int & partitionAddedCounter)277 static bool AddPartitions(const Disk &disk, const PartitonList &ulist, int &partitionAddedCounter)
278 {
279 if (!ulist.empty()) {
280 int userNum = GetPartitionNumByPartName(USERDATA_PARTNAME, disk.partList);
281 int step = 1;
282 char pdevname[DEVPATH_SIZE] = {0};
283 for (auto& p2 : ulist) {
284 if (p2->partName == USERDATA_PARTNAME) {
285 LOG(INFO) << "Change userdata image is not support.";
286 continue;
287 }
288 if (p2->partName == UPDATER_PARTNAME) {
289 LOG(ERROR) << "Change updater image is not supported.";
290 continue;
291 }
292 p2->partNum = userNum + step;
293 if (snprintf_s(pdevname, sizeof(pdevname), sizeof(pdevname) - 1, "%sp%d", MMC_DEV, p2->partNum) == -1) {
294 return false;
295 }
296 p2->devName.clear();
297 p2->devName = pdevname;
298 LOG(INFO) << "Adding partition " << p2->partName;
299 if (!DoAddPartition (disk, *p2)) {
300 LOG(ERROR) << "Add partition fail for " << p2->partName;
301 return false;
302 }
303 step++;
304 partitionAddedCounter++;
305 }
306 }
307 return true;
308 }
309
RemovePartitions(const Disk & disk,int & partitionRemovedCounter)310 static bool RemovePartitions(const Disk &disk, int &partitionRemovedCounter)
311 {
312 PartitonList pList = disk.partList;
313 for (const auto &it : pList) {
314 if (it->changeType == NOT_CHANGE) {
315 continue;
316 }
317 if (it->partName == UPDATER_PARTNAME) {
318 LOG(ERROR) << "Cannot delete updater partition.";
319 continue;
320 }
321
322 if (it->partName == USERDATA_PARTNAME) {
323 LOG(INFO) << "Cannot delete userdata partition.";
324 continue;
325 }
326 if (DoUmountDiskPartition(*it) == 0) {
327 continue;
328 }
329 LOG(INFO) << "Removing partition " << it->partName;
330 if (!DoRmPartition (disk, it->partNum)) {
331 LOG(ERROR) << "Remove partition failed.";
332 return false;
333 }
334 partitionRemovedCounter++;
335 }
336 return true;
337 }
338
CheckDevicePartitions(const std::string & path)339 int CheckDevicePartitions(const std::string &path)
340 {
341 if (DiskAlloc(path) == 0) {
342 LOG(ERROR) << "path not exist" << path;
343 return 0;
344 }
345 if (ProbeAllPartitions() == 0) {
346 LOG(ERROR) << "partition sum is zero!";
347 return 0;
348 }
349 return 1;
350 }
351
AdjustPartitions(Disk * disk,int & partitionChangedCounter)352 int AdjustPartitions(Disk *disk, int &partitionChangedCounter)
353 {
354 PartitonList ulist;
355 ulist.clear();
356
357 if (disk == nullptr || BlockDiskOpen(*disk) < 0) {
358 return 0;
359 }
360
361 if (GetRegisterUpdaterPartitionList(ulist) == 0) {
362 LOG(ERROR) << "get updater list fail!";
363 return 0;
364 }
365
366 if (!RemovePartitions(*disk, partitionChangedCounter)) {
367 return 0;
368 }
369
370 BlockSync(*disk);
371 if (!AddPartitions(*disk, ulist, partitionChangedCounter)) {
372 return 0;
373 }
374 BlockSync(*disk);
375 return 1;
376 }
377
DoPartitions(PartitonList & nlist)378 int DoPartitions(PartitonList &nlist)
379 {
380 LOG(INFO) << "do_partitions start";
381 if (nlist.empty()) {
382 LOG(ERROR) << "newpartitionlist is empty ";
383 return 0;
384 }
385
386 const std::string path = MMC_PATH;
387 if (CheckDevicePartitions(path) == 0) {
388 return 0;
389 }
390
391 Disk *disk = GetRegisterBlockDisk(path);
392 if (disk == nullptr) {
393 LOG(ERROR) << "getRegisterdisk fail! ";
394 return 0;
395 }
396 if (RegisterUpdaterPartitionList(nlist, disk->partList) == 0) {
397 LOG(ERROR) << "register updater list fail!";
398 free(disk);
399 return 0;
400 }
401
402 ON_SCOPE_EXIT(clearresource) {
403 BlockDiskClose(*disk);
404 DestroyDiskPartitions(*disk);
405 DestroyDiskDevices(*disk);
406 free(disk);
407 };
408
409 int partitionChangedCounter = 1;
410 if (AdjustPartitions(disk, partitionChangedCounter) == 0) {
411 return 0;
412 }
413
414 (void)WriteDiskPartitionToMisc(nlist);
415 return partitionChangedCounter;
416 }
417 } // Updater
418
419