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