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_manager.h"
17 
18 #include <sys/sysmacros.h>
19 #include <thread>
20 
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 
28 namespace OHOS {
29 namespace StorageDaemon {
30 DiskManager* DiskManager::instance_ = nullptr;
31 
Instance()32 DiskManager* DiskManager::Instance()
33 {
34     if (instance_ == nullptr) {
35         instance_ = new DiskManager();
36     }
37 
38     return instance_;
39 }
40 
~DiskManager()41 DiskManager::~DiskManager()
42 {
43     LOGI("Destroy DiskManager");
44 }
45 
HandleDiskEvent(NetlinkData * data)46 void DiskManager::HandleDiskEvent(NetlinkData *data)
47 {
48     if (data == nullptr) {
49         LOGE("data is nullptr");
50         return;
51     }
52     std::lock_guard<std::mutex> lock(lock_);
53     std::string devType = data->GetParam("DEVTYPE");
54     if (devType != "disk") {
55         return;
56     }
57 
58     unsigned int major = (unsigned int) std::stoi(data->GetParam("MAJOR"));
59     unsigned int minor = (unsigned int) std::stoi(data->GetParam("MINOR"));
60     dev_t device = makedev(major, minor);
61 
62     switch (data->GetAction()) {
63         case NetlinkData::Actions::ADD: {
64             auto diskInfo = MatchConfig(data);
65             if (diskInfo == nullptr) {
66                 LOGI("Can't match config, devPath is %{public}s", data->GetDevpath().c_str());
67             } else {
68                 CreateDisk(diskInfo);
69                 LOGI("Handle Disk Add Event");
70             }
71             break;
72         }
73         case NetlinkData::Actions::CHANGE: {
74             ChangeDisk(device);
75             LOGI("Handle Disk Change Event");
76             break;
77         }
78         case NetlinkData::Actions::REMOVE: {
79             DestroyDisk(device);
80             LOGI("Handle Disk Remove Event");
81             break;
82         }
83         default: {
84             LOGW("Cannot handle unexpected disk event %{public}d", data->GetAction());
85             break;
86         }
87     }
88 }
89 
MatchConfig(NetlinkData * data)90 std::shared_ptr<DiskInfo> DiskManager::MatchConfig(NetlinkData *data)
91 {
92     if (data == nullptr) {
93         LOGE("data is nullptr");
94         return nullptr;
95     }
96     std::string sysPath = data->GetSyspath();
97     std::string devPath = data->GetDevpath();
98     unsigned int major = (unsigned int) std::stoi(data->GetParam("MAJOR"));
99     unsigned int minor = (unsigned int) std::stoi(data->GetParam("MINOR"));
100     dev_t device = makedev(major, minor);
101 
102     for (auto config : diskConfig_) {
103         if ((config != nullptr) && config->IsMatch(devPath)) {
104             uint32_t flag = static_cast<uint32_t>(config->GetFlag());
105             if (major == DISK_MMC_MAJOR) {
106                 flag |= DiskInfo::DeviceFlag::SD_FLAG;
107             } else {
108                 flag |= DiskInfo::DeviceFlag::USB_FLAG;
109             }
110             auto diskInfo =  std::make_shared<DiskInfo>(sysPath, devPath, device, static_cast<int>(flag));
111             return diskInfo;
112         }
113     }
114 
115     LOGI("No matching configuration found");
116     return nullptr;
117 }
118 
CreateDisk(std::shared_ptr<DiskInfo> & diskInfo)119 void DiskManager::CreateDisk(std::shared_ptr<DiskInfo> &diskInfo)
120 {
121     if (diskInfo == nullptr) {
122         LOGE("diskInfo is nullptr");
123         return;
124     }
125 
126     int ret = diskInfo->Create();
127     if (ret != E_OK) {
128         LOGE("Create DiskInfo failed");
129         return;
130     }
131 
132     disk_.push_back(diskInfo);
133 }
134 
ChangeDisk(dev_t device)135 void DiskManager::ChangeDisk(dev_t device)
136 {
137     for (auto &diskInfo : disk_) {
138         if (diskInfo->GetDevice() == device) {
139             diskInfo->ReadMetadata();
140             diskInfo->ReadPartition();
141         }
142     }
143 }
144 
DestroyDisk(dev_t device)145 void DiskManager::DestroyDisk(dev_t device)
146 {
147     int ret;
148 
149     for (auto i = disk_.begin(); i != disk_.end();) {
150         if ((*i)->GetDevice() == device) {
151             ret = (*i)->Destroy();
152             if (ret != E_OK) {
153                 LOGE("Destroy DiskInfo failed");
154                 return;
155             }
156 
157             StorageManagerClient client;
158             ret = client.NotifyDiskDestroyed((*i)->GetId());
159             if (ret != E_OK) {
160                 LOGI("Notify Disk Destroyed failed");
161             }
162             i = disk_.erase(i);
163         } else {
164             i++;
165         }
166     }
167 }
168 
GetDisk(dev_t device)169 std::shared_ptr<DiskInfo> DiskManager::GetDisk(dev_t device)
170 {
171     for (auto &diskInfo : disk_) {
172         if ((diskInfo != nullptr) && (diskInfo->GetDevice() == device)) {
173             return diskInfo;
174         }
175     }
176 
177     LOGI("No disk found with the given device");
178     return nullptr;
179 }
180 
AddDiskConfig(std::shared_ptr<DiskConfig> & diskConfig)181 void DiskManager::AddDiskConfig(std::shared_ptr<DiskConfig> &diskConfig)
182 {
183     std::lock_guard<std::mutex> lock(lock_);
184     if (diskConfig != nullptr) {
185         diskConfig_.push_back(diskConfig);
186     }
187 }
188 
ReplayUevent()189 void DiskManager::ReplayUevent()
190 {
191     TraverseDirUevent(sysBlockPath_, true);
192 }
193 
HandlePartition(std::string diskId)194 int32_t DiskManager::HandlePartition(std::string diskId)
195 {
196     int32_t ret = E_NON_EXIST;
197 
198     for (auto i = disk_.begin(); i != disk_.end(); i++) {
199         if ((*i)->GetId() == diskId) {
200             ret = (*i)->Partition();
201             break;
202         }
203     }
204 
205     return ret;
206 }
207 } // namespace STORAGE_DAEMON
208 } // namespace OHOS
209