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
26 namespace Updater {
27 static struct Disk *g_disks;
DeviceStat(const BlockDevice & dev,struct stat & devStat)28 static 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
DeviceProbeType(BlockDevice & dev)41 static 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
LastComponent(const std::string & path)69 static 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
ReadDeviceSysfsFile(BlockDevice & dev,const std::string & file,std::string & strl)84 static 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
SdmmcGetProductInfo(BlockDevice & dev,std::string & type,std::string & name)111 static 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
SetBlockDeviceMode(BlockDevice & dev)121 bool 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
BlockDeviceClose(const BlockDevice & dev)142 static 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
ReadPartitionFromSys(const std::string & devname,const std::string & partn,const std::string & type,const std::string & table)151 static 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
InitGeneric(BlockDevice & dev,const std::string modelName)199 static 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
InitSdmmc(BlockDevice & dev)226 static 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
NewBlockDevice(const std::string & path)242 static 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
NewBlockDisk(const BlockDevice & dev,const DiskType diskType)291 static 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
DiskAlloc(const std::string & path)308 int 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
NewPartition(const BlockDevice & dev,int partn)327 static 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
GetPartition(const Disk & disk,int partn)380 struct 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
ProbeAllPartitions()398 int 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
GetRegisterBlockDisk(const std::string & path)420 Disk* 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
GetPartitionNumByPartName(const std::string & partname,const PartitonList & plist)432 int 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