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 "volume/external_volume_info.h"
17
18 #include <cstdlib>
19 #include <unistd.h>
20 #include <sys/stat.h>
21 #include <cerrno>
22 #include <sys/mount.h>
23 #include <csignal>
24 #include <algorithm>
25 #include <sys/wait.h>
26 #include <cstring>
27
28 #include "storage_service_log.h"
29 #include "storage_service_errno.h"
30 #include "utils/string_utils.h"
31 #include "volume/process.h"
32 #include "utils/file_utils.h"
33
34 using namespace std;
35 namespace OHOS {
36 namespace StorageDaemon {
GetBlkidData(const std::string type)37 std::string ExternalVolumeInfo::GetBlkidData(const std::string type)
38 {
39 std::vector<std::string> output;
40 std::vector<std::string> cmd = {
41 "blkid",
42 "-s",
43 type,
44 "-o",
45 "value",
46 devPath_
47 };
48
49 int32_t err = ForkExec(cmd, &output);
50 if (err) {
51 return "";
52 }
53
54 if (output.size() > 0) {
55 size_t sep = string::npos;
56 sep = output[0].find_first_of("\n");
57 if (sep != string::npos)
58 output[0].resize(sep);
59 return output[0];
60 }
61 return "";
62 }
63
ReadMetadata()64 int32_t ExternalVolumeInfo::ReadMetadata()
65 {
66 fsUuid_ = GetBlkidData("UUID");
67 fsType_ = GetBlkidData("TYPE");
68 fsLabel_ = GetBlkidData("LABEL");
69
70 if (fsUuid_.empty() || fsType_.empty()) {
71 LOGE("External volume ReadMetadata error.");
72 return E_ERR;
73 }
74 LOGI("ReadMetadata, fsUuid=%{public}s, fsType=%{public}d, fsLabel=%{public}s.",
75 GetFsUuid().c_str(), GetFsType(), GetFsLabel().c_str());
76 return E_OK;
77 }
78
GetFsType()79 int32_t ExternalVolumeInfo::GetFsType()
80 {
81 for (uint32_t i = 0; i < supportMountType_.size(); i++) {
82 if (supportMountType_[i].compare(fsType_) == 0) {
83 return i;
84 }
85 }
86 return -1;
87 }
88
GetFsUuid()89 std::string ExternalVolumeInfo::GetFsUuid()
90 {
91 return fsUuid_;
92 }
93
GetFsLabel()94 std::string ExternalVolumeInfo::GetFsLabel()
95 {
96 return fsLabel_;
97 }
98
DoCreate(dev_t dev)99 int32_t ExternalVolumeInfo::DoCreate(dev_t dev)
100 {
101 int32_t ret = 0;
102 string id = VolumeInfo::GetVolumeId();
103
104 device_ = dev;
105 devPath_ = StringPrintf(devPathDir_.c_str(), (id).c_str());
106
107 ret = mknod(devPath_.c_str(), S_IFBLK, dev);
108 if (ret) {
109 LOGE("External volume DoCreate error.");
110 return E_ERR;
111 }
112
113 ret = ReadMetadata();
114 if (ret) {
115 LOGE("External volume ReadMetadata failed.");
116 remove(devPath_.c_str());
117 return E_ERR;
118 }
119
120 return E_OK;
121 }
122
DoDestroy()123 int32_t ExternalVolumeInfo::DoDestroy()
124 {
125 int err = remove(devPath_.c_str());
126 if (err) {
127 LOGE("External volume DoDestroy error.");
128 return E_ERR;
129 }
130 return E_OK;
131 }
132
DoMount(const std::string mountPath,uint32_t mountFlags)133 int32_t ExternalVolumeInfo::DoMount(const std::string mountPath, uint32_t mountFlags)
134 {
135 int32_t ret = 0;
136 mode_t mode = 0777;
137
138 if (GetFsType() == -1) {
139 return E_NOT_SUPPORT;
140 }
141
142 if (fsType_ == "ext2" || fsType_ == "ext3" || fsType_ == "ext4") {
143 ret = mount(devPath_.c_str(), mountPath.c_str(), fsType_.c_str(), mountFlags, "");
144 if (!ret) {
145 TravelChmod(mountPath, mode);
146 }
147 } else if (fsType_ == "ntfs") {
148 std::vector<std::string> cmd = {
149 "mount.ntfs",
150 devPath_,
151 mountPath,
152 "-o",
153 "rw,uid=0,gid=0,dmask=000,fmask=000"
154 };
155 ret = ForkExec(cmd);
156 } else {
157 ret = mount(devPath_.c_str(), mountPath.c_str(), fsType_.c_str(), MS_MGC_VAL, "fmask=000,dmask=000");
158 }
159
160 if (ret) {
161 LOGE("External volume DoMount error.");
162 return E_MOUNT;
163 }
164
165 return E_OK;
166 }
167
DoUMount(const std::string mountPath,bool force)168 int32_t ExternalVolumeInfo::DoUMount(const std::string mountPath, bool force)
169 {
170 if (force) {
171 LOGI("External volume start force to unmount.");
172 Process ps(mountPath);
173 ps.UpdatePidByPath();
174 ps.KillProcess(SIGKILL);
175 umount2(mountPath.c_str(), MNT_DETACH);
176 remove(mountPath.c_str());
177 return E_OK;
178 }
179
180 int ret = umount(mountPath.c_str());
181 int err = remove(mountPath.c_str());
182 if (err && ret) {
183 LOGE("External volume DoUmount error.");
184 return E_UMOUNT;
185 }
186
187 if (err) {
188 LOGE("failed to call remove(%{public}s) error, errno = %{public}d", mountPath.c_str(), errno);
189 return E_SYS_CALL;
190 }
191 return E_OK;
192 }
193
DoCheck()194 int32_t ExternalVolumeInfo::DoCheck()
195 {
196 int32_t ret = ExternalVolumeInfo::ReadMetadata();
197 if (ret) {
198 LOGE("External volume uuid=%{public}s DoCheck failed.", GetFsUuid().c_str());
199 return E_ERR;
200 }
201
202 // check fstype
203 if (GetFsType() == -1) {
204 LOGE("External Volume type not support.");
205 return E_NOT_SUPPORT;
206 }
207 return E_OK;
208 }
209
DoFormat(std::string type)210 int32_t ExternalVolumeInfo::DoFormat(std::string type)
211 {
212 int32_t err = 0;
213 std::map<std::string, std::string>::iterator iter = supportFormatType_.find(type);
214 if (iter == supportFormatType_.end()) {
215 LOGE("External volume format not support.");
216 return E_NOT_SUPPORT;
217 }
218
219 if (type == "ext2" || type == "ext3" || type == "ext4") {
220 std::vector<std::string> cmd = {
221 iter->second,
222 "-F",
223 "-t",
224 type,
225 devPath_
226 };
227 err = ForkExec(cmd);
228 } else {
229 std::vector<std::string> cmd = {
230 iter->second,
231 devPath_
232 };
233 err = ForkExec(cmd);
234 }
235
236 if (err == E_NO_CHILD) {
237 err = E_OK;
238 }
239
240 ReadMetadata();
241 return err;
242 }
243 } // StorageDaemon
244 } // OHOS