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