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 std::string lineToken = " ";
215 status = sScan;
216 bool foundPart = false;
217 Table table = Table::UNKNOWN;
218 for (auto &line : lines) {
219 auto split = SplitLine(line, lineToken);
220 auto it = split.begin();
221 if (it == split.end()) {
222 continue;
223 }
224 if (*it == "DISK") {
225 if (++it == split.end()) {
226 continue;
227 }
228 if (*it == "mbr") {
229 table = Table::MBR;
230 } else if (*it == "gpt") {
231 table = Table::GPT;
232 } else {
233 LOGI("Unknown partition table %{public}s", (*it).c_str());
234 continue;
235 }
236 } else if (*it == "PART") {
237 if (++it == split.end()) {
238 continue;
239 }
240 int32_t index = std::stoi(*it);
241 if (index > maxVolumes || index < 1) {
242 LOGE("Invalid partition %{public}d", index);
243 continue;
244 }
245 dev_t partitionDev = makedev(major(device_), minor(device_) + static_cast<uint32_t>(index));
246 res = CreateVolume(partitionDev);
247 if (res == E_OK) {
248 foundPart = true;
249 }
250 }
251 }
252 if (table == Table::UNKNOWN || !foundPart) {
253 LOGI("%{public}s has unknown table", id_.c_str());
254 std::string fsType;
255 std::string uuid;
256 std::string label;
257 if (OHOS::StorageDaemon::ReadMetadata(devPath_, fsType, uuid, label) == E_OK) {
258 CreateVolume(device_);
259 } else {
260 LOGE("failed to identify the disk device");
261 return E_NON_EXIST;
262 }
263 }
264 return E_OK;
265 }
266
CreateVolume(dev_t dev)267 int DiskInfo::CreateVolume(dev_t dev)
268 {
269 auto volume = VolumeManager::Instance();
270
271 LOGI("disk read volume metadata");
272 std::string volumeId = volume->CreateVolume(GetId(), dev);
273 if (volumeId == "") {
274 LOGE("Create volume failed");
275 return E_ERR;
276 }
277
278 volumeId_.push_back(volumeId);
279 return E_OK;
280 }
281
Partition()282 int DiskInfo::Partition()
283 {
284 std::vector<std::string> cmd;
285 int res;
286
287 res = Destroy();
288 if (res != E_OK) {
289 LOGE("Destroy failed in Partition()");
290 }
291
292 cmd.push_back(SGDISK_PATH);
293 cmd.push_back(SGDISK_ZAP_CMD);
294 cmd.push_back(devPath_);
295 res = ForkExec(cmd);
296 if (res != E_OK) {
297 LOGE("sgdisk: zap fail");
298 return res;
299 }
300
301 cmd.clear();
302 cmd.push_back(SGDISK_PATH);
303 cmd.push_back(SGDISK_PART_CMD);
304 cmd.push_back(devPath_);
305 res = ForkExec(cmd);
306 if (res != E_OK) {
307 LOGE("sgdisk: partition fail");
308 return res;
309 }
310
311 return E_OK;
312 }
313 } // namespace STORAGE_DAEMON
314 } // namespace OHOS
315