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