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 33namespace Updater { 34namespace { 35constexpr const char *USERDATA_PARTNAME = "userdata"; 36constexpr const char *UPDATER_PARTNAME = "updater"; 37} 38 39static 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 57static 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 68static 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 81static int BlockSync(const Disk &disk) 82{ 83 if (disk.dev->readOnly) { 84 return 0; 85 } 86 DoFsync(*(disk.dev)); 87 return 1; 88} 89 90static 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 100static 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 109static 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 119static 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 141static 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 167static 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 183static 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 195static 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 205static 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 238static 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 277static 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 310static 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 339int 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 352int 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 378int 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