• 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 
16 #include "fs_manager/partitions.h"
17 #include <cstdlib>
18 #include <cstring>
19 #include <libgen.h>
20 #include <string>
21 #include <sys/stat.h>
22 #include <sys/sysmacros.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25 #include "fs_manager/cmp_partition.h"
26 #include "log/log.h"
27 #include "partition_const.h"
28 #include "securec.h"
29 
30 namespace updater {
31 static struct Disk *g_disks;
DeviceStat(const BlockDevice & dev,struct stat & devStat)32 static int DeviceStat(const BlockDevice &dev, struct stat &devStat)
33 {
34     int ret = 0;
35     if (!stat (dev.devPath.c_str(), &devStat)) {
36         ret = 1;
37     }
38     UPDATER_ERROR_CHECK(!stat (dev.devPath.c_str(), &devStat), "stat error: " << errno << std::endl, ret = 0);
39     return ret;
40 }
41 
DeviceProbeType(BlockDevice & dev)42 static int DeviceProbeType(BlockDevice &dev)
43 {
44     struct stat devStat {};
45     int devMajor;
46     int devMinor;
47     BlockSpecific *specific = BLOCK_SPECIFIC(&dev);
48 
49     UPDATER_CHECK_ONLY_RETURN(DeviceStat(dev, devStat), return 0);
50 
51     specific->major = devMajor = major (devStat.st_rdev);
52     specific->minor = devMinor = minor (devStat.st_rdev);
53     bool a1 = SCSI_BLK_MAJOR(devMajor) && (devMinor % 0x10 == 0);
54     bool a2 = devMajor == SDMMC_MAJOR && (devMinor % 0x08 == 0);
55     UPDATER_CHECK_ONLY_RETURN(!a1, dev.type = DEVICE_SCSI);
56     UPDATER_CHECK_ONLY_RETURN(!a2, dev.type = DEVICE_EMMC);
57     UPDATER_CHECK_ONLY_RETURN(a1 || a2, dev.type = DEVICE_UNKNOWN);
58     return 1;
59 }
60 
LastComponent(const std::string & path)61 static std::string LastComponent(const std::string &path)
62 {
63     std::string tmp = "";
64     if (path == MMC_PATH) {
65         tmp = MMC_DEV;
66     }
67     UPDATER_CHECK_ONLY_RETURN(path != SDA_PATH, tmp = SDA_DEV);
68     UPDATER_CHECK_ONLY_RETURN(path != SDB_PATH, tmp = SDB_DEV);
69     return tmp;
70 }
71 
ReadDeviceSysfsFile(BlockDevice & dev,const std::string & file,std::string & strl)72 static bool ReadDeviceSysfsFile(BlockDevice &dev, const std::string &file, std::string &strl)
73 {
74     FILE *f = nullptr;
75     char nameBuf[DEVPATH_SIZE];
76     char buf[BUFFER_SIZE];
77 
78     UPDATER_CHECK_ONLY_RETURN(snprintf_s(nameBuf, DEVPATH_SIZE, DEVPATH_SIZE - 1, "/sys/block/%s/device/%s",
79         LastComponent(dev.devPath).c_str(), file.c_str()) != -1, return false);
80     char *realPath = realpath(nameBuf, NULL);
81     UPDATER_CHECK_ONLY_RETURN(realPath != nullptr, return false);
82     UPDATER_CHECK_ONLY_RETURN((f = fopen(realPath, "r")) != nullptr, free(realPath); return false);
83 
84     UPDATER_CHECK_ONLY_RETURN(fgets(buf, BUFFER_SIZE, f) != nullptr, fclose(f); free(realPath); return false);
85     strl = buf;
86     fclose(f);
87     free(realPath);
88     return true;
89 }
90 
SdmmcGetProductInfo(BlockDevice & dev,std::string & type,std::string & name)91 static bool SdmmcGetProductInfo(BlockDevice &dev, std::string &type, std::string &name)
92 {
93     std::string typeStr = "type";
94     std::string nameStr = "name";
95 
96     bool ret = ReadDeviceSysfsFile(dev, typeStr, type);
97     bool red = ReadDeviceSysfsFile(dev, nameStr, name);
98     return (ret || red);
99 }
100 
SetBlockDeviceMode(BlockDevice & dev)101 bool SetBlockDeviceMode(BlockDevice &dev)
102 {
103     BlockSpecific *specific = BLOCK_SPECIFIC(&dev);
104 
105     specific->fd = open(dev.devPath.c_str(), RW_MODE);
106     if (specific->fd == -1) {
107         LOG(WARNING) << "Open " << dev.devPath << " with read-write failed, try read-only mode";
108         specific->fd = open(dev.devPath.c_str(), RD_MODE);
109         bool a1 = dev.readOnly;
110         dev.readOnly = 1;
111         if (specific->fd == -1) {
112             LOG(ERROR) << "Open " << dev.devPath << " with read-only mode failed: " << errno;
113             dev.readOnly = a1;
114             return false;
115         }
116     } else {
117         dev.readOnly = 0;
118     }
119     return true;
120 }
121 
BlockDeviceClose(const BlockDevice & dev)122 static int BlockDeviceClose(const BlockDevice &dev)
123 {
124     BlockSpecific* specific = BLOCK_SPECIFIC(&dev);
125     UPDATER_CHECK_ONLY_RETURN(fsync(specific->fd) >= 0 && close(specific->fd) >= 0, return 0);
126     return 1;
127 }
ReadPartitionFromSys(const std::string & devname,const std::string & partn,const std::string & type,const std::string & table)128 static std::string ReadPartitionFromSys(const std::string &devname, const std::string &partn,
129     const std::string &type, const std::string &table)
130 {
131     FILE *f = nullptr;
132     char nameBuf[DEVPATH_SIZE] = {0};
133     char buf[BUFFER_SIZE] = {0};
134     char *str = nullptr;
135     std::string partString = "";
136     char *partInf = (char *)calloc(BUFFER_SIZE, sizeof(char));
137     UPDATER_ERROR_CHECK(partInf, "Allocate memory for partInf failed.", return partString);
138     if (partn.empty()) {
139         UPDATER_CHECK_ONLY_RETURN(snprintf_s(nameBuf, DEVPATH_SIZE, DEVPATH_SIZE - 1, "/sys/block/%s/%s",
140             devname.c_str(), type.c_str()) != -1, free(partInf); return partString);
141     } else {
142         UPDATER_CHECK_ONLY_RETURN(snprintf_s(nameBuf, DEVPATH_SIZE, DEVPATH_SIZE - 1, "/sys/block/%s/%s/%s",
143             devname.c_str(), partn.c_str(), type.c_str()) != -1, free(partInf); return partString);
144     }
145     if ((f = fopen(nameBuf, "r")) == nullptr) {
146         free(partInf);
147         return partString;
148     }
149     while (!feof(f)) {
150         UPDATER_CHECK_ONLY_RETURN(fgets(buf, BUFFER_SIZE, f) != nullptr, fclose(f); free(partInf); return partString);
151         if (type == "uevent") {
152             str = strstr(buf, table.c_str());
153             if (str != nullptr) {
154                 UPDATER_CHECK_ONLY_RETURN(memcpy_s(partInf, BUFFER_SIZE, buf + table.size(),
155                 sizeof(buf) - table.size()) == 0, fclose(f); free(partInf); return partString);
156                 partInf[strlen(partInf) - 1] = '\0';
157                 partString = partInf;
158                 goto end;
159             }
160         } else if (type == "start") {
161             UPDATER_CHECK_ONLY_RETURN(memcpy_s(partInf, BUFFER_SIZE, buf, sizeof(buf) - 1) == 0,
162                                       fclose(f); free(partInf); return partString);
163             LOG(INFO) << "start partInf: " << partInf;
164             partString = partInf;
165             goto end;
166         } else if (type == "size") {
167             UPDATER_CHECK_ONLY_RETURN(memcpy_s(partInf, BUFFER_SIZE, buf, sizeof(buf) - 1) == 0,
168             fclose(f); free(partInf); return partString);
169             LOG(INFO) << "size partInf: " << partInf;
170             partString = partInf;
171             goto end;
172         }
173         UPDATER_CHECK_ONLY_RETURN(memset_s(buf, sizeof(buf), 0, sizeof(buf)) == 0, fclose(f);
174             free(partInf); return partString);
175     }
176     end:
177     free(partInf);
178     fclose(f);
179     return partString;
180 }
181 
InitGeneric(BlockDevice & dev,const std::string modelName)182 static int InitGeneric(BlockDevice &dev, const std::string modelName)
183 {
184     struct stat devStat {};
185     UPDATER_ERROR_CHECK(DeviceStat(dev, devStat), "device stat error ", return 0);
186     UPDATER_ERROR_CHECK(SetBlockDeviceMode(dev), "device authority error ", return 0);
187 
188     const std::string devName = LastComponent(dev.devPath);
189     std::string partSize = ReadPartitionFromSys(devName, "", "size", "");
190     UPDATER_CHECK_ONLY_RETURN(!partSize.empty(), return 0);
191     int devSize = atoi(partSize.c_str());
192     dev.length = devSize;
193     dev.sectorSize = SECTOR_SIZE_DEFAULT;
194     dev.physSectorSize = SECTOR_SIZE_DEFAULT;
195     dev.model = modelName;
196     BlockDeviceClose (dev);
197     dev.fd = -1;
198     return 1;
199 }
200 
InitSdmmc(BlockDevice & dev)201 static int InitSdmmc(BlockDevice &dev)
202 {
203     std::string type = "";
204     std::string name = "";
205     std::string id = "";
206     bool a1 = SdmmcGetProductInfo(dev, type, name);
207     if (a1) {
208         id = type + name;
209     }
210     UPDATER_CHECK_ONLY_RETURN(a1, id = "Generic SD/MMC Storage Card"; return 0);
211     return InitGeneric(dev, id);
212 }
213 
NewBlockDevice(const std::string & path)214 static BlockDevice* NewBlockDevice(const std::string &path)
215 {
216     BlockDevice *dev = nullptr;
217     BlockSpecific *specific = nullptr;
218 
219     dev = static_cast<BlockDevice*>(calloc(1, sizeof (BlockDevice)));
220     UPDATER_ERROR_CHECK(dev, "calloc errno " << errno, return nullptr);
221 
222     dev->devPath = path;
223     dev->specific = static_cast<BlockSpecific*>(calloc(1, sizeof (BlockSpecific)));
224     UPDATER_ERROR_CHECK(dev->specific, "calloc errno " << errno, free(dev);
225                 return nullptr);
226 
227     specific = BLOCK_SPECIFIC(dev);
228     dev->readOnly = 0;
229     dev->sectorSize = 0;
230     dev->physSectorSize = 0;
231 
232     int ret = 0;
233     bool a1 = DeviceProbeType(*dev);
234     if (a1) {
235         if (dev->type == DEVICE_EMMC)  {
236             ret = InitSdmmc(*dev);
237             UPDATER_ERROR_CHECK_NOT_RETURN(ret != 0, "Init sdmmc error");
238         }
239         UPDATER_WARNING_CHECK_NOT_RETURN(dev->type == DEVICE_EMMC, "Unsupported device type");
240     }
241     UPDATER_ERROR_CHECK_NOT_RETURN(a1, "Device probe error");
242 
243     UPDATER_CHECK_ONLY_RETURN(ret != 0, free(dev->specific); free(dev); dev = nullptr);
244     return dev;
245 }
246 
NewBlockDisk(const BlockDevice & dev,const DiskType diskType)247 static Disk* NewBlockDisk(const BlockDevice &dev, const DiskType diskType)
248 {
249     Disk *disk = nullptr;
250 
251     disk = static_cast<Disk*>(calloc (1, sizeof (Disk)));
252     UPDATER_ERROR_CHECK(disk, "Allocate memory for disk failed: " << errno, return nullptr);
253 
254     disk->dev = (BlockDevice*)&dev;
255     disk->type = diskType;
256     disk->partsum = 0;
257     disk->partList.clear();
258     return disk;
259 }
260 
DiskAlloc(const std::string & path)261 int DiskAlloc(const std::string &path)
262 {
263     struct Disk *disk = nullptr;
264     struct BlockDevice *dev = nullptr;
265     dev = NewBlockDevice(path);
266     UPDATER_ERROR_CHECK(dev, "NewBlockDevice nullptr ", return 0);
267 
268     disk = NewBlockDisk(*dev, GPT);
269     UPDATER_ERROR_CHECK(disk, "NewBlockDisk nullptr ", return 0);
270     g_disks = disk;
271     return 1;
272 }
273 
NewPartition(const BlockDevice & dev,int partn)274 static struct Partition* NewPartition(const BlockDevice &dev, int partn)
275 {
276     Partition* part = (Partition*) calloc (1, sizeof (Partition));
277     UPDATER_ERROR_CHECK(part, "Allocate memory for partition failed.", return nullptr);
278     const std::string devName = LastComponent(dev.devPath);
279     char partName[64] = {0};
280     if (devName == MMC_DEV) {
281         UPDATER_CHECK_ONLY_RETURN(snprintf_s(partName, sizeof(partName), sizeof(partName) - 1, "%sp%d",
282             devName.c_str(), partn) != -1, free(part); return nullptr);
283     }
284     UPDATER_CHECK_ONLY_RETURN(!(devName != MMC_DEV && ((devName == SDA_DEV) || (devName == SDB_DEV)) &&
285         snprintf_s(partName, sizeof(partName), sizeof(partName) - 1, "%s%d", devName.c_str(),
286         partn) == -1), free(part); return nullptr);
287 
288     std::string strstart = ReadPartitionFromSys(devName, partName, "start", "");
289     if (strstart.empty()) {
290         free(part);
291         return nullptr;
292     }
293     part->start = atoi(strstart.c_str());
294     std::string strsize = ReadPartitionFromSys(devName, partName, "size", "");
295     UPDATER_CHECK_ONLY_RETURN(!strsize.empty(), free(part); return nullptr);
296     part->length = atoi(strsize.c_str());
297 
298     std::string strdevname = ReadPartitionFromSys(devName, partName, "uevent", "DEVNAME=");
299     part->devName = partName;
300     if (!strdevname.empty()) {
301         part->devName = strdevname;
302     }
303     std::string strpartname = ReadPartitionFromSys(devName, partName, "uevent", "PARTNAME=");
304     part->partName = partName;
305     if (!strpartname.empty()) {
306         part->partName = strpartname;
307     }
308 
309     part->partNum = partn;
310     part->type = NORMAL;
311     part->fsType = "";
312     part->changeType = NORMAL_CHANGE;
313     return part;
314 }
315 
GetPartition(const Disk & disk,int partn)316 struct Partition* GetPartition(const Disk &disk, int partn)
317 {
318     struct Partition *part = nullptr;
319     UPDATER_CHECK_ONLY_RETURN(partn, return nullptr);
320     UPDATER_CHECK_ONLY_RETURN(!disk.partList.empty(), return nullptr);
321     for (auto& p : disk.partList) {
322         if (p->partNum == partn) {
323             part = p;
324             break;
325         }
326     }
327     return part;
328 }
329 
ProbeAllPartitions()330 int ProbeAllPartitions()
331 {
332     int i = 0;
333     struct Disk* disk = nullptr;
334     disk = g_disks;
335     UPDATER_CHECK_ONLY_RETURN(disk, return 0);
336     int partSum = DEFAULT_PARTSUM;
337     struct Partition* part = nullptr;
338     for (i = 1; i < partSum; i++) {
339         part = NewPartition(*(disk->dev), i);
340         if (!part) {
341             LOG(ERROR) << "Create new partition failed.";
342             break;
343         }
344         disk->partList.push_back(part);
345         disk->partsum++;
346     }
347     return disk->partsum;
348 }
349 
GetRegisterBlockDisk(const std::string & path)350 Disk* GetRegisterBlockDisk(const std::string &path)
351 {
352     UPDATER_CHECK_ONLY_RETURN(g_disks != nullptr, return nullptr);
353     Disk *p = nullptr;
354     if (g_disks->dev->devPath == path) {
355         p = g_disks;
356     }
357     return p;
358 }
359 
GetPartitionNumByPartName(const std::string & partname,const PartitonList & plist)360 int GetPartitionNumByPartName(const std::string &partname, const PartitonList &plist)
361 {
362     int ret = 0;
363     for (const auto &p : plist) {
364         if (p->partName == partname) {
365             ret = p->partNum;
366             break;
367         }
368     }
369     return ret;
370 }
371 } // namespace updater
372