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