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