• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         free(dev);
321         LOG(ERROR) << "NewBlockDevice nullptr ";
322         return 0;
323     }
324     g_disks = disk;
325     return 1;
326 }
327 
NewPartition(const BlockDevice & dev,int partn)328 static struct Partition* NewPartition(const BlockDevice &dev, int partn)
329 {
330     Partition* part = (Partition*) calloc (1, sizeof (Partition));
331     if (part == nullptr) {
332         LOG(ERROR) << "Allocate memory for partition failed.";
333         return nullptr;
334     }
335     const std::string devName = LastComponent(dev.devPath);
336     char partName[64] = {0};
337     if (devName == MMC_DEV) {
338         if (snprintf_s(partName, sizeof(partName), sizeof(partName) - 1, "%sp%d", devName.c_str(), partn) == -1) {
339             free(part);
340             return nullptr;
341         }
342     }
343     if (devName != MMC_DEV && ((devName == SDA_DEV) || (devName == SDB_DEV)) &&
344         snprintf_s(partName, sizeof(partName), sizeof(partName) - 1, "%s%d", devName.c_str(), partn) == -1) {
345         free(part);
346         return nullptr;
347     }
348 
349     std::string strstart = ReadPartitionFromSys(devName, partName, "start", "");
350     if (strstart.empty()) {
351         free(part);
352         return nullptr;
353     }
354     part->start = static_cast<size_t>(atoi(strstart.c_str()));
355 
356     std::string strsize = ReadPartitionFromSys(devName, partName, "size", "");
357     if (strsize.empty()) {
358         free(part);
359         return nullptr;
360     }
361     part->length = static_cast<size_t>(atoi(strsize.c_str()));
362 
363     std::string strdevname = ReadPartitionFromSys(devName, partName, "uevent", "DEVNAME=");
364     part->devName = partName;
365     if (!strdevname.empty()) {
366         part->devName = strdevname;
367     }
368     std::string strpartname = ReadPartitionFromSys(devName, partName, "uevent", "PARTNAME=");
369     part->partName = partName;
370     if (!strpartname.empty()) {
371         part->partName = strpartname;
372     }
373 
374     part->partNum = partn;
375     part->type = NORMAL;
376     part->fsType = "";
377     part->changeType = NORMAL_CHANGE;
378     return part;
379 }
380 
GetPartition(const Disk & disk,int partn)381 struct Partition* GetPartition(const Disk &disk, int partn)
382 {
383     struct Partition *part = nullptr;
384     if (partn == 0) {
385         return nullptr;
386     }
387     if (disk.partList.empty()) {
388         return nullptr;
389     }
390     for (auto& p : disk.partList) {
391         if (p->partNum == partn) {
392             part = p;
393             break;
394         }
395     }
396     return part;
397 }
398 
ProbeAllPartitions()399 int ProbeAllPartitions()
400 {
401     int i = 0;
402     struct Disk* disk = nullptr;
403     disk = g_disks;
404     if (disk == nullptr) {
405         return 0;
406     }
407     int partSum = DEFAULT_PARTSUM;
408     struct Partition* part = nullptr;
409     for (i = 1; i < partSum; i++) {
410         part = NewPartition(*(disk->dev), i);
411         if (!part) {
412             LOG(ERROR) << "Create new partition failed.";
413             break;
414         }
415         disk->partList.push_back(part);
416         disk->partsum++;
417     }
418     return disk->partsum;
419 }
420 
GetRegisterBlockDisk(const std::string & path)421 Disk* GetRegisterBlockDisk(const std::string &path)
422 {
423     if (g_disks == nullptr) {
424         return nullptr;
425     }
426     Disk *p = nullptr;
427     if (g_disks->dev->devPath == path) {
428         p = g_disks;
429     }
430     return p;
431 }
432 
GetPartitionNumByPartName(const std::string & partname,const PartitonList & plist)433 int GetPartitionNumByPartName(const std::string &partname, const PartitonList &plist)
434 {
435     int ret = 0;
436     for (const auto &p : plist) {
437         if (p->partName == partname) {
438             ret = p->partNum;
439             break;
440         }
441     }
442     return ret;
443 }
444 } // namespace Updater
445