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 "fs_manager/partitions.h" 16#include <cstdlib> 17#include <string> 18#include <sys/stat.h> 19#include <sys/sysmacros.h> 20#include <unistd.h> 21#include "log/log.h" 22#include "partition_const.h" 23#include "scope_guard.h" 24#include "securec.h" 25 26namespace Updater { 27static struct Disk *g_disks; 28static int DeviceStat(const BlockDevice &dev, struct stat &devStat) 29{ 30 int ret = 0; 31 if (!stat (dev.devPath.c_str(), &devStat)) { 32 ret = 1; 33 } 34 if (stat (dev.devPath.c_str(), &devStat) != EOK) { 35 LOG(ERROR) << "stat error: " << errno << std::endl; 36 ret = 0; 37 } 38 return ret; 39} 40 41static int DeviceProbeType(BlockDevice &dev) 42{ 43 struct stat devStat {}; 44 int devMajor; 45 int devMinor; 46 BlockSpecific *specific = BLOCK_SPECIFIC(&dev); 47 if (DeviceStat(dev, devStat) == 0) { 48 return 0; 49 } 50 51 devMajor = static_cast<int>(major (devStat.st_rdev)); 52 specific->major = devMajor; 53 devMinor = static_cast<int>(minor (devStat.st_rdev)); 54 specific->minor = devMinor; 55 bool a1 = SCSI_BLK_MAJOR(devMajor) && (devMinor % 0x10 == 0); 56 bool a2 = devMajor == SDMMC_MAJOR && (devMinor % 0x08 == 0); 57 if (a1) { 58 dev.type = DEVICE_SCSI; 59 } 60 if (a2) { 61 dev.type = DEVICE_EMMC; 62 } 63 if (!a1 && !a2) { 64 dev.type = DEVICE_UNKNOWN; 65 } 66 return 1; 67} 68 69static std::string LastComponent(const std::string &path) 70{ 71 std::string tmp = ""; 72 if (path == MMC_PATH) { 73 tmp = MMC_DEV; 74 } 75 if (path == SDA_PATH) { 76 tmp = SDA_DEV; 77 } 78 if (path == SDB_PATH) { 79 tmp = SDB_DEV; 80 } 81 return tmp; 82} 83 84static bool ReadDeviceSysfsFile(BlockDevice &dev, const std::string &file, std::string &strl) 85{ 86 FILE *f = nullptr; 87 char nameBuf[DEVPATH_SIZE]; 88 char buf[BUFFER_SIZE]; 89 90 if (snprintf_s(nameBuf, DEVPATH_SIZE, DEVPATH_SIZE - 1, "/sys/block/%s/device/%s", 91 LastComponent(dev.devPath).c_str(), file.c_str()) == -1) { 92 return false; 93 } 94 char realPath[PATH_MAX] = {0}; 95 if (realpath(nameBuf, realPath) == nullptr) { 96 return false; 97 } 98 if ((f = fopen(realPath, "r")) == nullptr) { 99 return false; 100 } 101 102 if (fgets(buf, BUFFER_SIZE, f) == nullptr) { 103 fclose(f); 104 return false; 105 } 106 strl = buf; 107 fclose(f); 108 return true; 109} 110 111static bool SdmmcGetProductInfo(BlockDevice &dev, std::string &type, std::string &name) 112{ 113 std::string typeStr = "type"; 114 std::string nameStr = "name"; 115 116 bool ret = ReadDeviceSysfsFile(dev, typeStr, type); 117 bool red = ReadDeviceSysfsFile(dev, nameStr, name); 118 return (ret || red); 119} 120 121bool SetBlockDeviceMode(BlockDevice &dev) 122{ 123 BlockSpecific *specific = BLOCK_SPECIFIC(&dev); 124 125 specific->fd = open(dev.devPath.c_str(), RW_MODE); 126 if (specific->fd == -1) { 127 LOG(WARNING) << "Open " << dev.devPath << " with read-write failed, try read-only mode"; 128 specific->fd = open(dev.devPath.c_str(), RD_MODE); 129 bool a1 = dev.readOnly; 130 dev.readOnly = 1; 131 if (specific->fd == -1) { 132 LOG(ERROR) << "Open " << dev.devPath << " with read-only mode failed: " << errno; 133 dev.readOnly = a1; 134 return false; 135 } 136 } else { 137 dev.readOnly = 0; 138 } 139 return true; 140} 141 142static int BlockDeviceClose(const BlockDevice &dev) 143{ 144 BlockSpecific* specific = BLOCK_SPECIFIC(&dev); 145 if (fsync(specific->fd) < 0 || close(specific->fd) < 0) { 146 return 0; 147 } 148 return 1; 149} 150 151static std::string ReadPartitionFromSys(const std::string &devname, const std::string &partn, 152 const std::string &type, const std::string &table) 153{ 154 FILE *f = nullptr; 155 char buf[BUFFER_SIZE] = {0}; 156 std::string devPath; 157 std::string partString = ""; 158 devPath = "/sys/block/" + devname + "/" + partn + "/" + type; 159 if (partn.empty()) { 160 devPath = "/sys/block/" + devname + "/" + type; 161 } 162 163 if (devPath.length() >= DEVPATH_SIZE) { 164 LOG(ERROR) << "devPath is invalid"; 165 return partString; 166 } 167 168 if ((f = fopen(devPath.c_str(), "r")) == nullptr) { 169 return partString; 170 } 171 172 ON_SCOPE_EXIT(fclosef) { 173 fclose(f); 174 }; 175 176 while (!feof(f)) { 177 if (fgets(buf, BUFFER_SIZE, f) == nullptr) { 178 return partString; 179 } 180 if (type == "uevent" && strstr(buf, table.c_str()) != nullptr) { 181 partString = std::string(buf + table.size(), sizeof(buf) - table.size()); 182 if (!partString.empty()) { 183 partString.pop_back(); 184 } 185 return partString; 186 } else if (type == "start" || type == "size") { 187 partString = std::string(buf, sizeof(buf) - 1); 188 LOG(INFO) << type << " partInf: " << std::string(buf, sizeof(buf) - 1); 189 return partString; 190 } 191 if (memset_s(buf, sizeof(buf), 0, sizeof(buf)) != EOK) { 192 return partString; 193 } 194 } 195 196 return partString; 197} 198 199static int InitGeneric(BlockDevice &dev, const std::string modelName) 200{ 201 struct stat devStat {}; 202 if (DeviceStat(dev, devStat) == 0) { 203 LOG(ERROR) << "device stat error "; 204 return 0; 205 } 206 if (!SetBlockDeviceMode(dev)) { 207 LOG(ERROR) << "device authority error "; 208 return 0; 209 } 210 211 const std::string devName = LastComponent(dev.devPath); 212 std::string partSize = ReadPartitionFromSys(devName, "", "size", ""); 213 if (partSize.empty()) { 214 return 0; 215 } 216 int devSize = atoi(partSize.c_str()); 217 dev.length = devSize; 218 dev.sectorSize = SECTOR_SIZE_DEFAULT; 219 dev.physSectorSize = SECTOR_SIZE_DEFAULT; 220 dev.model = modelName; 221 BlockDeviceClose (dev); 222 dev.fd = -1; 223 return 1; 224} 225 226static int InitSdmmc(BlockDevice &dev) 227{ 228 std::string type = ""; 229 std::string name = ""; 230 std::string id = ""; 231 bool a1 = SdmmcGetProductInfo(dev, type, name); 232 if (a1) { 233 id = type + name; 234 } 235 if (!a1) { 236 id = "Generic SD/MMC Storage Card"; 237 return 0; 238 } 239 return InitGeneric(dev, id); 240} 241 242static BlockDevice* NewBlockDevice(const std::string &path) 243{ 244 BlockDevice *dev = nullptr; 245 BlockSpecific *specific = nullptr; 246 247 dev = static_cast<BlockDevice*>(calloc(1, sizeof (BlockDevice))); 248 if (dev == nullptr) { 249 LOG(ERROR) << "calloc errno " << errno; 250 return nullptr; 251 } 252 253 dev->devPath = path; 254 dev->specific = static_cast<BlockSpecific*>(calloc(1, sizeof (BlockSpecific))); 255 if (!dev->specific) { 256 LOG(ERROR) << "calloc errno " << errno; 257 free(dev); 258 return nullptr; 259 } 260 261 specific = BLOCK_SPECIFIC(dev); 262 dev->readOnly = 0; 263 dev->sectorSize = 0; 264 dev->physSectorSize = 0; 265 266 int ret = 0; 267 bool a1 = DeviceProbeType(*dev); 268 if (a1) { 269 if (dev->type == DEVICE_EMMC) { 270 ret = InitSdmmc(*dev); 271 if (ret == 0) { 272 LOG(ERROR) << "Init sdmmc error"; 273 } 274 } 275 if (dev->type != DEVICE_EMMC) { 276 LOG(WARNING) << "Unsupported device type"; 277 } 278 } 279 if (!a1) { 280 LOG(ERROR) << "Device probe error"; 281 } 282 283 if (ret == 0) { 284 free(dev->specific); 285 free(dev); 286 dev = nullptr; 287 } 288 return dev; 289} 290 291static Disk* NewBlockDisk(const BlockDevice &dev, const DiskType diskType) 292{ 293 Disk *disk = nullptr; 294 295 disk = static_cast<Disk*>(calloc (1, sizeof (Disk))); 296 if (disk == nullptr) { 297 LOG(ERROR) << "Allocate memory for disk failed: " << errno; 298 return nullptr; 299 } 300 301 disk->dev = (BlockDevice*)&dev; 302 disk->type = diskType; 303 disk->partsum = 0; 304 disk->partList.clear(); 305 return disk; 306} 307 308int DiskAlloc(const std::string &path) 309{ 310 struct Disk *disk = nullptr; 311 struct BlockDevice *dev = nullptr; 312 dev = NewBlockDevice(path); 313 if (dev == nullptr) { 314 LOG(ERROR) << "NewBlockDevice nullptr "; 315 return 0; 316 } 317 318 disk = NewBlockDisk(*dev, GPT); 319 if (disk == nullptr) { 320 LOG(ERROR) << "NewBlockDevice nullptr "; 321 return 0; 322 } 323 g_disks = disk; 324 return 1; 325} 326 327static struct Partition* NewPartition(const BlockDevice &dev, int partn) 328{ 329 Partition* part = (Partition*) calloc (1, sizeof (Partition)); 330 if (part == nullptr) { 331 LOG(ERROR) << "Allocate memory for partition failed."; 332 return nullptr; 333 } 334 const std::string devName = LastComponent(dev.devPath); 335 char partName[64] = {0}; 336 if (devName == MMC_DEV) { 337 if (snprintf_s(partName, sizeof(partName), sizeof(partName) - 1, "%sp%d", devName.c_str(), partn) == -1) { 338 free(part); 339 return nullptr; 340 } 341 } 342 if (devName != MMC_DEV && ((devName == SDA_DEV) || (devName == SDB_DEV)) && 343 snprintf_s(partName, sizeof(partName), sizeof(partName) - 1, "%s%d", devName.c_str(), partn) == -1) { 344 free(part); 345 return nullptr; 346 } 347 348 std::string strstart = ReadPartitionFromSys(devName, partName, "start", ""); 349 if (strstart.empty()) { 350 free(part); 351 return nullptr; 352 } 353 part->start = static_cast<size_t>(atoi(strstart.c_str())); 354 355 std::string strsize = ReadPartitionFromSys(devName, partName, "size", ""); 356 if (strsize.empty()) { 357 free(part); 358 return nullptr; 359 } 360 part->length = static_cast<size_t>(atoi(strsize.c_str())); 361 362 std::string strdevname = ReadPartitionFromSys(devName, partName, "uevent", "DEVNAME="); 363 part->devName = partName; 364 if (!strdevname.empty()) { 365 part->devName = strdevname; 366 } 367 std::string strpartname = ReadPartitionFromSys(devName, partName, "uevent", "PARTNAME="); 368 part->partName = partName; 369 if (!strpartname.empty()) { 370 part->partName = strpartname; 371 } 372 373 part->partNum = partn; 374 part->type = NORMAL; 375 part->fsType = ""; 376 part->changeType = NORMAL_CHANGE; 377 return part; 378} 379 380struct Partition* GetPartition(const Disk &disk, int partn) 381{ 382 struct Partition *part = nullptr; 383 if (partn == 0) { 384 return nullptr; 385 } 386 if (disk.partList.empty()) { 387 return nullptr; 388 } 389 for (auto& p : disk.partList) { 390 if (p->partNum == partn) { 391 part = p; 392 break; 393 } 394 } 395 return part; 396} 397 398int ProbeAllPartitions() 399{ 400 int i = 0; 401 struct Disk* disk = nullptr; 402 disk = g_disks; 403 if (disk == nullptr) { 404 return 0; 405 } 406 int partSum = DEFAULT_PARTSUM; 407 struct Partition* part = nullptr; 408 for (i = 1; i < partSum; i++) { 409 part = NewPartition(*(disk->dev), i); 410 if (!part) { 411 LOG(ERROR) << "Create new partition failed."; 412 break; 413 } 414 disk->partList.push_back(part); 415 disk->partsum++; 416 } 417 return disk->partsum; 418} 419 420Disk* GetRegisterBlockDisk(const std::string &path) 421{ 422 if (g_disks == nullptr) { 423 return nullptr; 424 } 425 Disk *p = nullptr; 426 if (g_disks->dev->devPath == path) { 427 p = g_disks; 428 } 429 return p; 430} 431 432int GetPartitionNumByPartName(const std::string &partname, const PartitonList &plist) 433{ 434 int ret = 0; 435 for (const auto &p : plist) { 436 if (p->partName == partname) { 437 ret = p->partNum; 438 break; 439 } 440 } 441 return ret; 442} 443} // namespace Updater 444