• 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 = 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