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