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