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 "disk/disk_info.h"
17
18 #include <sys/sysmacros.h>
19
20 #include "disk/disk_manager.h"
21 #include "ipc/storage_manager_client.h"
22 #include "storage_service_errno.h"
23 #include "storage_service_log.h"
24 #include "utils/disk_utils.h"
25 #include "utils/file_utils.h"
26 #include "utils/string_utils.h"
27 #include "volume/volume_manager.h"
28
29 namespace OHOS {
30 namespace StorageDaemon {
31 constexpr unsigned int MAJORID_BLKEXT = 259;
32 constexpr unsigned int MAX_PARTITION = 16;
33 const std::string SGDISK_PATH = "/system/bin/sgdisk";
34 const std::string SGDISK_DUMP_CMD = "--ohos-dump";
35 const std::string SGDISK_ZAP_CMD = "--zap-all";
36 const std::string SGDISK_PART_CMD = "--new=0:0:-0 --typeconde=0:0c00 --gpttombr=1";
37
38 enum class Table {
39 UNKNOWN,
40 MBR,
41 GPT,
42 };
43
DiskInfo(std::string sysPath,std::string devPath,dev_t device,int flag)44 DiskInfo::DiskInfo(std::string sysPath, std::string devPath, dev_t device, int flag)
45 {
46 id_ = StringPrintf("disk-%d-%d", major(device), minor(device));
47 sysPath_ = sysPath;
48 eventPath_ = devPath;
49 devPath_ = StringPrintf("/dev/block/%s", id_.c_str());
50 device_ = device;
51 flags_ = static_cast<unsigned int>(flag);
52 status = sInital;
53 }
54
GetDevice() const55 dev_t DiskInfo::GetDevice() const
56 {
57 return device_;
58 }
59
GetId() const60 std::string DiskInfo::GetId() const
61 {
62 return id_;
63 }
64
GetDevPath() const65 std::string DiskInfo::GetDevPath() const
66 {
67 return devPath_;
68 }
69
GetDevDSize() const70 uint64_t DiskInfo::GetDevDSize() const
71 {
72 return size_;
73 }
74
GetSysPath() const75 std::string DiskInfo::GetSysPath() const
76 {
77 return sysPath_;
78 }
79
GetDevVendor() const80 std::string DiskInfo::GetDevVendor() const
81 {
82 return vendor_;
83 }
84
GetDevFlag() const85 int DiskInfo::GetDevFlag() const
86 {
87 return flags_;
88 }
89
~DiskInfo()90 DiskInfo::~DiskInfo()
91 {
92 DestroyDiskNode(devPath_);
93 }
94
Create()95 int DiskInfo::Create()
96 {
97 int ret;
98
99 CreateDiskNode(devPath_, device_);
100 status = sCreate;
101 ReadMetadata();
102
103 StorageManagerClient client;
104 ret = client.NotifyDiskCreated(*this);
105 if (ret != E_OK) {
106 LOGE("Notify Disk Created failed");
107 return ret;
108 }
109
110 ret = ReadPartition();
111 if (ret != E_OK) {
112 LOGE("Create disk failed");
113 return ret;
114 }
115
116 return E_OK;
117 }
118
Destroy()119 int DiskInfo::Destroy()
120 {
121 auto volume = VolumeManager::Instance();
122
123 for (auto volumeId : volumeId_) {
124 auto ret = volume->DestroyVolume(volumeId);
125 if (ret != E_OK) {
126 LOGE("Destroy volume %{public}s failed", volumeId.c_str());
127 return E_ERR;
128 }
129 }
130 status = sDestroy;
131 volumeId_.clear();
132 return E_OK;
133 }
134
ReadMetadata()135 void DiskInfo::ReadMetadata()
136 {
137 size_ = -1;
138 vendor_.clear();
139 if (GetDevSize(devPath_, &size_) != E_OK) {
140 size_ = -1;
141 }
142
143 unsigned int majorId = major(device_);
144 if (majorId == DISK_MMC_MAJOR) {
145 std::string path(sysPath_ + "/device/manfid");
146 std::string str;
147 if (!ReadFile(path, &str)) {
148 LOGE("open file %{public}s failed", path.c_str());
149 return;
150 }
151 int manfid = std::stoi(str);
152 switch (manfid) {
153 case 0x000003: {
154 vendor_ = "SanDisk";
155 break;
156 }
157 case 0x00001b: {
158 vendor_ = "SamSung";
159 break;
160 }
161 case 0x000028: {
162 vendor_ = "Lexar";
163 break;
164 }
165 case 0x000074: {
166 vendor_ = "Transcend";
167 break;
168 }
169 default : {
170 vendor_ = "Unknown";
171 LOGI("Unknown vendor information: %{public}d", manfid);
172 break;
173 }
174 }
175 } else {
176 std::string path(sysPath_ + "/device/vendor");
177 std::string str;
178 if (!ReadFile(path, &str)) {
179 LOGE("open file %{public}s failed", path.c_str());
180 return;
181 }
182 vendor_ = str;
183 LOGI("Read metadata %{public}s", path.c_str());
184 }
185 }
186
ReadPartition()187 int DiskInfo::ReadPartition()
188 {
189 int maxVolumes = GetMaxVolume(device_);
190 if (maxVolumes < 0) {
191 LOGE("Invaild maxVolumes: %{public}d", maxVolumes);
192 return E_ERR;
193 }
194
195 std::vector<std::string> cmd;
196 std::vector<std::string> output;
197 std::vector<std::string> lines;
198 int res;
199
200 cmd.push_back(SGDISK_PATH);
201 cmd.push_back(SGDISK_DUMP_CMD);
202 cmd.push_back(devPath_);
203 res = ForkExec(cmd, &output);
204 if (res != E_OK) {
205 LOGE("get %{private}s partition failed", devPath_.c_str());
206 return res;
207 }
208 std::string bufToken = "\n";
209 for (auto &buf : output) {
210 auto split = SplitLine(buf, bufToken);
211 for (auto &tmp : split)
212 lines.push_back(tmp);
213 }
214
215 status = sScan;
216 return ReadDiskLines(lines, maxVolumes);
217 }
218
CreateMBRVolume(int32_t type,dev_t dev)219 bool DiskInfo::CreateMBRVolume(int32_t type, dev_t dev)
220 {
221 // FAT16 || NTFS/EXFAT || W95 FAT32 || W95 FAT32 || W95 FAT16 || EFI FAT32
222 if (type == 0x06 || type == 0x07 || type == 0x0b || type == 0x0c || type == 0x0e || type == 0x1b) {
223 if (CreateVolume(dev) == E_OK) {
224 return true;
225 }
226 }
227 return false;
228 }
229
CreateUnknownTabVol()230 int32_t DiskInfo::CreateUnknownTabVol()
231 {
232 LOGI("%{public}s has unknown table", id_.c_str());
233 std::string fsType;
234 std::string uuid;
235 std::string label;
236 if (OHOS::StorageDaemon::ReadMetadata(devPath_, fsType, uuid, label) == E_OK) {
237 CreateVolume(device_);
238 } else {
239 LOGE("failed to identify the disk device");
240 return E_NON_EXIST;
241 }
242 return E_OK;
243 }
244
ReadDiskLines(std::vector<std::string> lines,int32_t maxVols)245 int32_t DiskInfo::ReadDiskLines(std::vector<std::string> lines, int32_t maxVols)
246 {
247 std::string lineToken = " ";
248 bool foundPart = false;
249 Table table = Table::UNKNOWN;
250 for (auto &line : lines) {
251 auto split = SplitLine(line, lineToken);
252 auto it = split.begin();
253 if (it == split.end()) {
254 continue;
255 }
256
257 if (*it == "DISK") {
258 if (++it == split.end()) {
259 continue;
260 }
261 if (*it == "mbr") {
262 table = Table::MBR;
263 } else if (*it == "gpt") {
264 table = Table::GPT;
265 } else {
266 LOGI("Unknown partition table %{public}s", (*it).c_str());
267 continue;
268 }
269 } else if (*it == "PART") {
270 ProcessPartition(it, split.end(), table, maxVols, foundPart);
271 }
272 }
273
274 if (table == Table::UNKNOWN || !foundPart) {
275 return CreateUnknownTabVol();
276 }
277
278 return E_OK;
279 }
280
ProcessPartition(std::vector<std::string>::iterator & it,const std::vector<std::string>::iterator & end,Table table,int32_t maxVols,bool & foundPart)281 void DiskInfo::ProcessPartition(std::vector<std::string>::iterator &it, const std::vector<std::string>::iterator &end,
282 Table table, int32_t maxVols, bool &foundPart)
283 {
284 if (++it == end) {
285 return;
286 }
287 int32_t index = std::stoi(*it);
288 unsigned int majorId = major(device_);
289 if ((index > maxVols && majorId == DISK_MMC_MAJOR) || index < 1) {
290 LOGE("Invalid partition %{public}d", index);
291 return;
292 }
293 dev_t partitionDev = (index > MAX_SCSI_VOLUMES) ?
294 makedev(MAJORID_BLKEXT, minor(device_) + static_cast<uint32_t>(index) - MAX_PARTITION) :
295 makedev(major(device_), minor(device_) + static_cast<uint32_t>(index));
296 if (table == Table::MBR) {
297 if (++it == end) {
298 return;
299 }
300 int32_t type = std::stoi("0x0" + *it, 0, 16);
301 foundPart = CreateMBRVolume(type, partitionDev);
302 if (CreateMBRVolume(type, partitionDev)) {
303 foundPart = true;
304 } else {
305 LOGE("Create MBR Volume failed");
306 }
307 } else if (table == Table::GPT) {
308 if (CreateVolume(partitionDev) == E_OK) {
309 foundPart = true;
310 }
311 }
312 }
313
CreateVolume(dev_t dev)314 int DiskInfo::CreateVolume(dev_t dev)
315 {
316 auto volume = VolumeManager::Instance();
317
318 LOGI("disk read volume metadata");
319 std::string volumeId = volume->CreateVolume(GetId(), dev);
320 if (volumeId == "") {
321 LOGE("Create volume failed");
322 return E_ERR;
323 }
324
325 volumeId_.push_back(volumeId);
326 return E_OK;
327 }
328
Partition()329 int DiskInfo::Partition()
330 {
331 std::vector<std::string> cmd;
332 int res;
333
334 res = Destroy();
335 if (res != E_OK) {
336 LOGE("Destroy failed in Partition()");
337 }
338
339 cmd.push_back(SGDISK_PATH);
340 cmd.push_back(SGDISK_ZAP_CMD);
341 cmd.push_back(devPath_);
342 res = ForkExec(cmd);
343 if (res != E_OK) {
344 LOGE("sgdisk: zap fail");
345 return res;
346 }
347
348 cmd.clear();
349 cmd.push_back(SGDISK_PATH);
350 cmd.push_back(SGDISK_PART_CMD);
351 cmd.push_back(devPath_);
352 res = ForkExec(cmd);
353 if (res != E_OK) {
354 LOGE("sgdisk: partition fail");
355 return res;
356 }
357
358 return E_OK;
359 }
360 } // namespace STORAGE_DAEMON
361 } // namespace OHOS
362