• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = realpath(miscDevPath.c_str(), NULL);
209     if (realPath == nullptr) {
210         LOG(ERROR) << "realPath is NULL";
211         return false;
212     }
213     FILE *fp = fopen(realPath, "rb+");
214     free(realPath);
215     if (fp == nullptr) {
216         LOG(ERROR) << "fopen error " << errno;
217         return false;
218     }
219 
220     ON_SCOPE_EXIT(flosefp) {
221         fclose(fp);
222     };
223 
224     if (fseek(fp, offset, SEEK_SET) != 0) {
225         LOG(ERROR) << "fseek error";
226         return false;
227     }
228 
229     if (fwrite(msg.c_str(), msg.length() + 1, 1, fp) < 0) {
230         LOG(ERROR) << "fwrite error " << errno;
231         return false;
232     }
233 
234     int fd = fileno(fp);
235     fsync(fd);
236     return true;
237 }
238 
WriteDiskPartitionToMisc(PartitonList & nlist)239 static bool WriteDiskPartitionToMisc(PartitonList &nlist)
240 {
241     if (nlist.empty()) {
242         return false;
243     }
244     char blkdevparts[MISC_RECORD_UPDATE_PARTITIONS_SIZE] = "mmcblk0:";
245     std::sort(nlist.begin(), nlist.end(), [](const struct Partition *a, const struct Partition *b) {
246             return (a->start < b->start);
247     }); // Sort in ascending order
248     char tmp[SMALL_BUFFER_SIZE] = {0};
249     size_t size = 0;
250     for (auto& p : nlist) {
251         if (memset_s(tmp, sizeof(tmp), 0, sizeof(tmp)) != EOK) {
252             return false;
253         }
254         if (p->partName == "userdata") {
255             if (snprintf_s(tmp, sizeof(tmp), sizeof(tmp) - 1, "-(%s),",
256                 p->partName.c_str()) == -1) {
257                     return false;
258                 }
259         } else {
260             size = static_cast<size_t>(p->length * SECTOR_SIZE_DEFAULT / DEFAULT_SIZE_1MB);
261             if (snprintf_s(tmp, sizeof(tmp), sizeof(tmp) - 1, "%luM(%s),",
262                 size, p->partName.c_str()) == -1) {
263                     return false;
264                 }
265         }
266         if (strncat_s(blkdevparts, MISC_RECORD_UPDATE_PARTITIONS_SIZE - 1, tmp, strlen(tmp)) != EOK) {
267             LOG(ERROR) << "Block device name overflow";
268             return false;
269         }
270     }
271 
272     blkdevparts[strlen(blkdevparts) - 1] = '\0';
273     LOG(INFO) << "blkdevparts is " << blkdevparts;
274 
275     return WriteMiscMsgWithOffset(std::string(blkdevparts), MISC_RECORD_UPDATE_PARTITIONS_OFFSET);
276 }
277 
AddPartitions(const Disk & disk,const PartitonList & ulist,int & partitionAddedCounter)278 static bool AddPartitions(const Disk &disk, const PartitonList &ulist, int &partitionAddedCounter)
279 {
280     if (!ulist.empty()) {
281         int userNum = GetPartitionNumByPartName(USERDATA_PARTNAME, disk.partList);
282         int step = 1;
283         char pdevname[DEVPATH_SIZE] = {0};
284         for (auto& p2 : ulist) {
285             if (p2->partName == USERDATA_PARTNAME) {
286                 LOG(INFO) << "Change userdata image is not support.";
287                 continue;
288             }
289             if (p2->partName == UPDATER_PARTNAME) {
290                 LOG(ERROR) << "Change updater image is not supported.";
291                 continue;
292             }
293             p2->partNum = userNum + step;
294             if (snprintf_s(pdevname, sizeof(pdevname), sizeof(pdevname) - 1, "%sp%d", MMC_DEV, p2->partNum) == -1) {
295                 return false;
296             }
297             p2->devName.clear();
298             p2->devName = pdevname;
299             LOG(INFO) << "Adding partition " << p2->partName;
300             if (!DoAddPartition (disk, *p2)) {
301                 LOG(ERROR) << "Add partition fail for " << p2->partName;
302                 return false;
303             }
304             step++;
305             partitionAddedCounter++;
306         }
307     }
308     return true;
309 }
310 
RemovePartitions(const Disk & disk,int & partitionRemovedCounter)311 static bool RemovePartitions(const Disk &disk, int &partitionRemovedCounter)
312 {
313     PartitonList pList = disk.partList;
314     for (const auto &it : pList) {
315         if (it->changeType == NOT_CHANGE) {
316             continue;
317         }
318         if (it->partName == UPDATER_PARTNAME) {
319             LOG(ERROR) << "Cannot delete updater partition.";
320             continue;
321         }
322 
323         if (it->partName == USERDATA_PARTNAME) {
324             LOG(INFO) << "Cannot delete userdata partition.";
325             continue;
326         }
327         if (DoUmountDiskPartition(*it) == 0) {
328             continue;
329         }
330         LOG(INFO) << "Removing partition " << it->partName;
331         if (!DoRmPartition (disk, it->partNum)) {
332             LOG(ERROR) << "Remove partition failed.";
333             return false;
334         }
335         partitionRemovedCounter++;
336     }
337     return true;
338 }
339 
CheckDevicePartitions(const std::string & path)340 int CheckDevicePartitions(const std::string &path)
341 {
342     if (DiskAlloc(path) == 0) {
343         LOG(ERROR) << "path not exist" << path;
344         return 0;
345     }
346     if (ProbeAllPartitions() == 0) {
347         LOG(ERROR) << "partition sum  is zero!";
348         return 0;
349     }
350     return 1;
351 }
352 
AdjustPartitions(Disk * disk,int & partitionChangedCounter)353 int AdjustPartitions(Disk *disk, int &partitionChangedCounter)
354 {
355     PartitonList ulist;
356     ulist.clear();
357 
358     if (disk == nullptr || BlockDiskOpen(*disk) < 0) {
359         return 0;
360     }
361 
362     if (GetRegisterUpdaterPartitionList(ulist) == 0) {
363         LOG(ERROR) << "get updater list fail!";
364         return 0;
365     }
366 
367     if (!RemovePartitions(*disk, partitionChangedCounter)) {
368         return 0;
369     }
370 
371     BlockSync(*disk);
372     if (!AddPartitions(*disk, ulist, partitionChangedCounter)) {
373         return 0;
374     }
375     BlockSync(*disk);
376     return 1;
377 }
378 
DoPartitions(PartitonList & nlist)379 int DoPartitions(PartitonList &nlist)
380 {
381     LOG(INFO) << "do_partitions start";
382     if (nlist.empty()) {
383         LOG(ERROR) << "newpartitionlist is empty ";
384         return 0;
385     }
386 
387     const std::string path = MMC_PATH;
388     if (CheckDevicePartitions(path) == 0) {
389         return 0;
390     }
391 
392     Disk *disk = GetRegisterBlockDisk(path);
393     if (disk == nullptr) {
394         LOG(ERROR) << "getRegisterdisk fail! ";
395         return 0;
396     }
397     if (RegisterUpdaterPartitionList(nlist, disk->partList) == 0) {
398         LOG(ERROR) << "register updater list fail!";
399         free(disk);
400         return 0;
401     }
402 
403     ON_SCOPE_EXIT(clearresource) {
404         BlockDiskClose(*disk);
405         DestroyDiskPartitions(*disk);
406         DestroyDiskDevices(*disk);
407         free(disk);
408     };
409 
410     int partitionChangedCounter = 1;
411     if (AdjustPartitions(disk, partitionChangedCounter) == 0) {
412         return 0;
413     }
414 
415     (void)WriteDiskPartitionToMisc(nlist);
416     return partitionChangedCounter;
417 }
418 } // Updater
419 
420