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