1 /*
2 * Copyright (c) 2021-2025 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 "utils/file_utils.h"
17
18 #include <dirent.h>
19 #include <fcntl.h>
20 #include <fstream>
21 #include <sys/stat.h>
22 #include <sys/wait.h>
23 #include <unistd.h>
24 #include "parameters.h"
25 #include "securec.h"
26 #include "storage_service_errno.h"
27 #include "storage_service_log.h"
28 #include "string_ex.h"
29 #ifdef USE_LIBRESTORECON
30 #include "policycoreutils.h"
31 #endif
32 #ifdef EXTERNAL_STORAGE_QOS_TRANS
33 #include "concurrent_task_client.h"
34 #endif
35 namespace OHOS {
36 namespace StorageDaemon {
37 constexpr uint32_t ALL_PERMS = (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO);
38 #ifdef EXTERNAL_STORAGE_QOS_TRANS
39 constexpr int SET_SCHED_LOAD_TRANS_TYPE = 10001;
40 #endif
41 constexpr int BUF_LEN = 1024;
42 constexpr int PIPE_FD_LEN = 2;
43 constexpr uint8_t KILL_RETRY_TIME = 5;
44 constexpr uint32_t KILL_RETRY_INTERVAL_MS = 100 * 1000;
45 constexpr const char *MOUNT_POINT_INFO = "/proc/mounts";
46 constexpr const char *FUSE_PARAM_SERVICE_ENTERPRISE_ENABLE = "const.enterprise.external_storage_device.manage.enable";
47
RedirectStdToPipe(int logpipe[PIPE_FD_LEN],size_t len)48 int32_t RedirectStdToPipe(int logpipe[PIPE_FD_LEN], size_t len)
49 {
50 if (logpipe == nullptr || len < PIPE_FD_LEN) {
51 LOGE("std to pipe param is invalid.");
52 return E_ERR;
53 }
54 int ret = E_OK;
55 (void)close(logpipe[0]);
56 if (dup2(logpipe[1], STDOUT_FILENO) == -1) {
57 LOGE("dup2 stdout failed, errno is %{public}d.", errno);
58 ret = E_ERR;
59 }
60 if (dup2(logpipe[1], STDERR_FILENO) == -1) {
61 LOGE("dup2 stderr failed, errno is %{public}d.", errno);
62 ret = E_ERR;
63 }
64 (void)close(logpipe[1]);
65 return ret;
66 }
67
ChMod(const std::string & path,mode_t mode)68 int32_t ChMod(const std::string &path, mode_t mode)
69 {
70 return TEMP_FAILURE_RETRY(chmod(path.c_str(), mode));
71 }
72
ChOwn(const std::string & path,uid_t uid,gid_t gid)73 int32_t ChOwn(const std::string &path, uid_t uid, gid_t gid)
74 {
75 return TEMP_FAILURE_RETRY(chown(path.c_str(), uid, gid));
76 }
77
MkDir(const std::string & path,mode_t mode)78 int32_t MkDir(const std::string &path, mode_t mode)
79 {
80 return TEMP_FAILURE_RETRY(mkdir(path.c_str(), mode));
81 }
82
RmDir(const std::string & path)83 int32_t RmDir(const std::string &path)
84 {
85 return TEMP_FAILURE_RETRY(rmdir(path.c_str()));
86 }
87
Mount(const std::string & source,const std::string & target,const char * type,unsigned long flags,const void * data)88 int32_t Mount(const std::string &source, const std::string &target, const char *type,
89 unsigned long flags, const void *data)
90 {
91 return TEMP_FAILURE_RETRY(mount(source.c_str(), target.c_str(), type, flags, data));
92 }
93
UMount(const std::string & path)94 int32_t UMount(const std::string &path)
95 {
96 return TEMP_FAILURE_RETRY(umount(path.c_str()));
97 }
98
UMount2(const std::string & path,int flag)99 int32_t UMount2(const std::string &path, int flag)
100 {
101 return TEMP_FAILURE_RETRY(umount2(path.c_str(), flag));
102 }
103
IsDir(const std::string & path)104 bool IsDir(const std::string &path)
105 {
106 // check whether the path exists
107 struct stat st;
108 int ret = TEMP_FAILURE_RETRY(lstat(path.c_str(), &st));
109 if (ret) {
110 return false;
111 }
112
113 return S_ISDIR(st.st_mode);
114 }
115
IsFile(const std::string & path)116 bool IsFile(const std::string &path)
117 {
118 // check whether the path exists
119 struct stat buf = {};
120 if (stat(path.c_str(), &buf) != 0) {
121 return false;
122 }
123 return S_ISREG(buf.st_mode);
124 }
125
IsUsbFuse()126 bool IsUsbFuse()
127 {
128 bool ret = system::GetBoolParameter(FUSE_PARAM_SERVICE_ENTERPRISE_ENABLE, false);
129 LOGI("IsUsbFuse result: %{public}s.", ret ? "true" : "false");
130 return ret;
131 }
132
MkDirRecurse(const std::string & path,mode_t mode)133 bool MkDirRecurse(const std::string& path, mode_t mode)
134 {
135 std::string::size_type index = 0;
136 do {
137 std::string subPath = path;
138 index = path.find('/', index + 1);
139 if (index != std::string::npos) {
140 subPath = path.substr(0, index);
141 }
142
143 if (TEMP_FAILURE_RETRY(access(subPath.c_str(), F_OK)) != 0) {
144 if (MkDir(subPath, mode) != 0 && errno != EEXIST) {
145 return false;
146 }
147 }
148 } while (index != std::string::npos);
149
150 return TEMP_FAILURE_RETRY(access(path.c_str(), F_OK)) == 0;
151 }
152
153 // On success, true is returned. On error, false is returned, and errno is set appropriately.
PrepareDir(const std::string & path,mode_t mode,uid_t uid,gid_t gid)154 bool PrepareDir(const std::string &path, mode_t mode, uid_t uid, gid_t gid)
155 {
156 LOGI("prepare for %{public}s", path.c_str());
157 struct stat st;
158 if (TEMP_FAILURE_RETRY(lstat(path.c_str(), &st)) == E_ERR) {
159 if (errno != ENOENT) {
160 LOGE("failed to lstat, errno %{public}d", errno);
161 return false;
162 }
163 } else {
164 if (!S_ISDIR(st.st_mode)) {
165 LOGE("%{public}s exists and is not a directory", path.c_str());
166 return false;
167 }
168 if (((st.st_mode & ALL_PERMS) != mode) && ChMod(path, mode)) {
169 LOGE("dir exists and failed to chmod, errno %{public}d, uid %{public}d, gid %{public}d, mode %{public}d",
170 errno, st.st_uid, st.st_gid, st.st_mode);
171 if (TEMP_FAILURE_RETRY(lstat(path.c_str(), &st)) == E_ERR) {
172 LOGE("failed to lstat for chmod, errno %{public}d", errno);
173 }
174 return false;
175 }
176 if (((st.st_uid != uid) || (st.st_gid != gid)) && ChOwn(path, uid, gid)) {
177 LOGE("dir exists and failed to chown, errno %{public}d, uid %{public}d, gid %{public}d, mode %{public}d",
178 errno, st.st_uid, st.st_gid, st.st_mode);
179 if (TEMP_FAILURE_RETRY(lstat(path.c_str(), &st)) == E_ERR) {
180 LOGE("failed to lstat for chown, errno %{public}d", errno);
181 }
182 return false;
183 }
184 return true;
185 }
186 mode_t mask = umask(0);
187 if (MkDir(path, mode)) {
188 LOGE("failed to mkdir, errno %{public}d", errno);
189 umask(mask);
190 return false;
191 }
192 umask(mask);
193 if (ChMod(path, mode)) {
194 LOGE("failed to chmod, errno %{public}d", errno);
195 return false;
196 }
197 if (ChOwn(path, uid, gid)) {
198 LOGE("failed to chown, errno %{public}d", errno);
199 return false;
200 }
201 return RestoreconDir(path);
202 }
203
RmDirRecurse(const std::string & path)204 bool RmDirRecurse(const std::string &path)
205 {
206 LOGD("rm dir %{public}s", path.c_str());
207 DIR *dir = opendir(path.c_str());
208 if (!dir) {
209 if (errno == ENOENT) {
210 return true;
211 }
212
213 LOGE("failed to open dir %{public}s, errno %{public}d", path.c_str(), errno);
214 return false;
215 }
216
217 for (struct dirent *ent = readdir(dir); ent != nullptr; ent = readdir(dir)) {
218 if (ent->d_type == DT_DIR) {
219 if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
220 continue;
221 }
222
223 if (!RmDirRecurse(path + "/" + ent->d_name)) {
224 LOGE("failed to RmDirRecurse %{public}s, errno %{public}d", path.c_str(), errno);
225 (void)closedir(dir);
226 return false;
227 }
228 } else {
229 if (unlink((path + "/" + ent->d_name).c_str())) {
230 LOGE("failed to unlink file %{public}s, errno %{public}d", ent->d_name, errno);
231 (void)closedir(dir);
232 return false;
233 }
234 }
235 }
236
237 (void)closedir(dir);
238 if (rmdir(path.c_str())) {
239 LOGE("failed to rm dir %{public}s, errno %{public}d", path.c_str(), errno);
240 return false;
241 }
242 return true;
243 }
244
TravelChmod(const std::string & path,mode_t mode)245 void TravelChmod(const std::string &path, mode_t mode)
246 {
247 struct stat st;
248 DIR *d = nullptr;
249 struct dirent *dp = nullptr;
250 const char *skip1 = ".";
251 const char *skip2 = "..";
252
253 if (stat(path.c_str(), &st) < 0 || !S_ISDIR(st.st_mode)) {
254 LOGE("invalid path");
255 return;
256 }
257
258 (void)ChMod(path, mode);
259 if (!(d = opendir(path.c_str()))) {
260 LOGE("opendir failed");
261 return;
262 }
263
264 while ((dp = readdir(d)) != nullptr) {
265 if ((!strncmp(dp->d_name, skip1, strlen(skip1))) || (!strncmp(dp->d_name, skip2, strlen(skip2)))) {
266 continue;
267 }
268 std::string subpath = path + "/" + dp->d_name;
269 stat(subpath.c_str(), &st);
270 (void)ChMod(subpath, mode);
271 if (S_ISDIR(st.st_mode)) {
272 TravelChmod(subpath, mode);
273 }
274 }
275 (void)closedir(d);
276 }
277
StringToUint32(const std::string & str,uint32_t & num)278 bool StringToUint32(const std::string &str, uint32_t &num)
279 {
280 if (str.empty()) {
281 return false;
282 }
283 if (!IsNumericStr(str)) {
284 LOGE("Not numeric entry");
285 return false;
286 }
287
288 int value;
289 if (!StrToInt(str, value)) {
290 LOGE("String to int convert failed");
291 return false;
292 }
293 num = static_cast<uint32_t>(value);
294
295 return true;
296 }
297
StringToBool(const std::string & str,bool & result)298 bool StringToBool(const std::string &str, bool &result)
299 {
300 if (str.empty()) {
301 LOGE("String is empty.");
302 return false;
303 }
304
305 if (str == "true") {
306 result = true;
307 } else if (str == "false") {
308 result = false;
309 } else {
310 LOGE("Invalid boolean string: %{public}s", str.c_str());
311 return false;
312 }
313
314 return true;
315 }
316
GetSubDirs(const std::string & path,std::vector<std::string> & dirList)317 void GetSubDirs(const std::string &path, std::vector<std::string> &dirList)
318 {
319 dirList.clear();
320
321 struct stat st;
322 int ret = TEMP_FAILURE_RETRY(lstat(path.c_str(), &st));
323 if (ret != 0 || ((st.st_mode & S_IFDIR) != S_IFDIR)) {
324 LOGE("path is not dir");
325 return;
326 }
327
328 DIR *dir = opendir(path.c_str());
329 if (!dir) {
330 LOGE("failed to open dir %{public}s, errno %{public}d", path.c_str(), errno);
331 return;
332 }
333
334 for (struct dirent *ent = readdir(dir); ent != nullptr; ent = readdir(dir)) {
335 if ((ent->d_type != DT_DIR) ||
336 (strcmp(ent->d_name, ".") == 0) ||
337 (strcmp(ent->d_name, "..") == 0)) {
338 continue;
339 }
340 dirList.push_back(ent->d_name);
341 }
342
343 (void)closedir(dir);
344 }
345
ReadDigitDir(const std::string & path,std::vector<FileList> & dirInfo)346 void ReadDigitDir(const std::string &path, std::vector<FileList> &dirInfo)
347 {
348 struct stat st;
349 int ret = TEMP_FAILURE_RETRY(lstat(path.c_str(), &st));
350 if (ret != 0 || ((st.st_mode & S_IFDIR) != S_IFDIR)) {
351 LOGE("path is not dir");
352 return;
353 }
354
355 DIR *dir = opendir(path.c_str());
356 if (!dir) {
357 LOGE("failed to open dir %{public}s, errno %{public}d", path.c_str(), errno);
358 return;
359 }
360
361 for (struct dirent *ent = readdir(dir); ent != nullptr; ent = readdir(dir)) {
362 if ((ent->d_type != DT_DIR) ||
363 (strcmp(ent->d_name, ".") == 0) ||
364 (strcmp(ent->d_name, "..") == 0)) {
365 continue;
366 }
367
368 uint32_t userId;
369 std::string name(ent->d_name);
370 if (!StringToUint32(name, userId)) {
371 continue;
372 }
373 FileList entry = {
374 .userId = userId,
375 .path = path + "/" + name
376 };
377 dirInfo.push_back(entry);
378 }
379
380 (void)closedir(dir);
381 }
382
OpenSubFile(const std::string & path,std::vector<std::string> & file)383 void OpenSubFile(const std::string &path, std::vector<std::string> &file)
384 {
385 struct stat st;
386 int ret = TEMP_FAILURE_RETRY(lstat(path.c_str(), &st));
387 if (ret != 0 || ((st.st_mode & S_IFDIR) != S_IFDIR)) {
388 LOGI("path is not dir");
389 return;
390 }
391
392 DIR *dir = opendir(path.c_str());
393 if (!dir) {
394 LOGI("failed to open dir %{public}s, errno %{public}d", path.c_str(), errno);
395 return;
396 }
397 for (struct dirent *ent = readdir(dir); ent != nullptr; ent = readdir(dir)) {
398 if ((ent->d_type != DT_DIR)) {
399 std::string name(ent->d_name);
400 std::string filePath = path + "/" + name;
401 LOGI("filePath is %{public}s", filePath.c_str());
402 file.push_back(filePath);
403 continue;
404 } else {
405 if ((strcmp(ent->d_name, ".") == 0) || (strcmp(ent->d_name, "..") == 0)) {
406 continue;
407 }
408 std::string name(ent->d_name);
409 std::string filePath = path + "/" + name;
410 OpenSubFile(filePath, file);
411 }
412 }
413 (void)closedir(dir);
414 }
415
ReadFile(const std::string & path,std::string * str)416 bool ReadFile(const std::string &path, std::string *str)
417 {
418 std::ifstream infile;
419 int cnt = 0;
420
421 std::string rpath(PATH_MAX + 1, '\0');
422 if ((path.length() > PATH_MAX) || (realpath(path.c_str(), rpath.data()) == nullptr)) {
423 LOGE("realpath failed");
424 return false;
425 }
426
427 infile.open(rpath.c_str());
428 if (!infile) {
429 LOGE("Cannot open file");
430 return false;
431 }
432
433 while (1) {
434 std::string subStr;
435 infile >> subStr;
436 if (subStr == "") {
437 break;
438 }
439 cnt++;
440 *str = *str + subStr + '\n';
441 }
442
443 infile.close();
444 return cnt == 0 ? false : true;
445 }
446
FromatCmd(std::vector<std::string> & cmd)447 static std::vector<char*> FromatCmd(std::vector<std::string> &cmd)
448 {
449 std::vector<char*>res;
450 res.reserve(cmd.size() + 1);
451
452 for (auto& line : cmd) {
453 LOGI("cmd %{public}s", line.c_str());
454 res.emplace_back(const_cast<char*>(line.c_str()));
455 }
456 res.emplace_back(nullptr);
457
458 return res;
459 }
460
ForkExec(std::vector<std::string> & cmd,std::vector<std::string> * output)461 int ForkExec(std::vector<std::string> &cmd, std::vector<std::string> *output)
462 {
463 int pipe_fd[PIPE_FD_LEN];
464 pid_t pid;
465 int status;
466 auto args = FromatCmd(cmd);
467 if (pipe(pipe_fd) < 0) {
468 LOGE("creat pipe failed, errno is %{public}d.", errno);
469 return E_CREATE_PIPE;
470 }
471 pid = fork();
472 if (pid == -1) {
473 LOGE("fork failed, errno is %{public}d.", errno);
474 return E_FORK;
475 } else if (pid == 0) {
476 if (RedirectStdToPipe(pipe_fd, PIPE_FD_LEN)) {
477 _exit(1);
478 }
479 execvp(args[0], const_cast<char **>(args.data()));
480 LOGE("execvp failed errno: %{public}d", errno);
481 _exit(1);
482 } else {
483 (void)close(pipe_fd[1]);
484 if (output) {
485 char buf[BUF_LEN] = { 0 };
486 (void)memset_s(buf, sizeof(buf), 0, sizeof(buf));
487 output->clear();
488 while (read(pipe_fd[0], buf, BUF_LEN - 1) > 0) {
489 LOGI("get result %{public}s", buf);
490 output->push_back(buf);
491 }
492 }
493 (void)close(pipe_fd[0]);
494 waitpid(pid, &status, 0);
495 if (errno == ECHILD) {
496 return E_NO_CHILD;
497 }
498 if (!WIFEXITED(status)) {
499 LOGE("Process exits abnormally, errno is %{public}d, status is %{public}d", errno, status);
500 return E_WIFEXITED;
501 }
502 if (WEXITSTATUS(status) != 0) {
503 LOGE("Process exited with an error, errno is %{public}d, status is %{public}d", errno, status);
504 return E_WEXITSTATUS;
505 }
506 }
507 return E_OK;
508 }
509
ForkExecWithExit(std::vector<std::string> & cmd)510 int ForkExecWithExit(std::vector<std::string> &cmd)
511 {
512 int pipe_fd[2];
513 pid_t pid;
514 int status;
515 auto args = FromatCmd(cmd);
516
517 if (pipe(pipe_fd) < 0) {
518 LOGE("creat pipe failed");
519 return E_CREATE_PIPE;
520 }
521
522 pid = fork();
523 if (pid == -1) {
524 LOGE("fork failed");
525 return E_FORK;
526 } else if (pid == 0) {
527 (void)close(pipe_fd[0]);
528 if (dup2(pipe_fd[1], STDOUT_FILENO) == -1) {
529 LOGE("dup2 failed");
530 _exit(1);
531 }
532 (void)close(pipe_fd[1]);
533 execvp(args[0], const_cast<char **>(args.data()));
534 LOGE("execvp failed errno: %{public}d", errno);
535 _exit(1);
536 } else {
537 (void)close(pipe_fd[1]);
538 (void)close(pipe_fd[0]);
539 waitpid(pid, &status, 0);
540 LOGE("Process exits %{public}d", errno);
541 if (!WIFEXITED(status)) {
542 LOGE("Process exits abnormally, status: %{public}d", status);
543 return E_WIFEXITED;
544 }
545 if (WEXITSTATUS(status) != 0) {
546 LOGE("Process exited with an error, status: %{public}d", status);
547 return E_WEXITSTATUS;
548 }
549 }
550 return E_OK;
551 }
552
553 #ifdef EXTERNAL_STORAGE_QOS_TRANS
ReportExecutorPidEvent(std::vector<std::string> & cmd,int32_t pid)554 static void ReportExecutorPidEvent(std::vector<std::string> &cmd, int32_t pid)
555 {
556 std::unordered_map<std::string, std::string> payloads;
557 if (!cmd.empty() && (cmd[0] == "mount.ntfs" || cmd[0] == "mount.exfat")) {
558 payloads["value"] = std::to_string(1);
559 payloads["pid"] = std::to_string(pid);
560 OHOS::ConcurrentTask::ConcurrentTaskClient::GetInstance().ReportSceneInfo(
561 SET_SCHED_LOAD_TRANS_TYPE, payloads);
562 }
563 }
564
ClosePipe(int pipedes[PIPE_FD_LEN],size_t len)565 static void ClosePipe(int pipedes[PIPE_FD_LEN], size_t len)
566 {
567 if (pipedes == nullptr || len < PIPE_FD_LEN) {
568 LOGE("close pipe param is invalid.");
569 return;
570 }
571 (void)close(pipedes[0]);
572 (void)close(pipedes[1]);
573 }
574
WritePidToPipe(int pipe_fd[PIPE_FD_LEN],size_t len)575 static void WritePidToPipe(int pipe_fd[PIPE_FD_LEN], size_t len)
576 {
577 if (pipe_fd == nullptr || len < PIPE_FD_LEN) {
578 LOGE("write pipe param is invalid.");
579 return;
580 }
581 (void)close(pipe_fd[0]);
582 int send_pid = (int)getpid();
583 if (write(pipe_fd[1], &send_pid, sizeof(int)) == -1) {
584 LOGE("write pipe failed, errno is %{public}d.", errno);
585 _exit(1);
586 }
587 (void)close(pipe_fd[1]);
588 }
589
ReadPidFromPipe(std::vector<std::string> & cmd,int pipe_fd[2])590 static void ReadPidFromPipe(std::vector<std::string> &cmd, int pipe_fd[2])
591 {
592 (void)close(pipe_fd[1]);
593 int recv_pid;
594 while (read(pipe_fd[0], &recv_pid, sizeof(int)) > 0) {
595 LOGI("read child pid: %{public}d", recv_pid);
596 }
597 (void)close(pipe_fd[0]);
598 ReportExecutorPidEvent(cmd, recv_pid);
599 }
600
ReadLogFromPipe(int logpipe[PIPE_FD_LEN],size_t len)601 static void ReadLogFromPipe(int logpipe[PIPE_FD_LEN], size_t len)
602 {
603 if (logpipe == nullptr || len < PIPE_FD_LEN) {
604 LOGE("read pipe param is invalid.");
605 return;
606 }
607 (void)close(logpipe[1]);
608 FILE* fp = fdopen(logpipe[0], "r");
609 if (fp) {
610 char line[BUF_LEN];
611 while (fgets(line, sizeof(line), fp)) {
612 LOGI("exec exfat log: %{public}s", line);
613 }
614 fclose(fp);
615 return;
616 }
617 LOGE("open pipe file failed, errno is %{public}d.", errno);
618 (void)close(logpipe[0]);
619 }
620
ExtStorageMountForkExec(std::vector<std::string> & cmd)621 int ExtStorageMountForkExec(std::vector<std::string> &cmd)
622 {
623 int pipe_fd[PIPE_FD_LEN];
624 int pipe_log_fd[PIPE_FD_LEN]; /* for mount.exfat log*/
625 pid_t pid;
626 int status;
627 auto args = FromatCmd(cmd);
628
629 if (pipe(pipe_fd) < 0) {
630 LOGE("creat pipe failed, errno is %{public}d.", errno);
631 return E_ERR;
632 }
633
634 if (pipe(pipe_log_fd) < 0) {
635 LOGE("creat pipe for log failed, errno is %{public}d.", errno);
636 ClosePipe(pipe_fd, PIPE_FD_LEN);
637 return E_ERR;
638 }
639
640 pid = fork();
641 if (pid == -1) {
642 LOGE("fork failed, errno is %{public}d.", errno);
643 ClosePipe(pipe_fd, PIPE_FD_LEN);
644 ClosePipe(pipe_log_fd, PIPE_FD_LEN);
645 return E_ERR;
646 } else if (pid == 0) {
647 WritePidToPipe(pipe_fd, PIPE_FD_LEN);
648 if (RedirectStdToPipe(pipe_log_fd, PIPE_FD_LEN)) {
649 _exit(1);
650 }
651 execvp(args[0], const_cast<char **>(args.data()));
652 LOGE("execvp failed errno: %{public}d", errno);
653 _exit(1);
654 } else {
655 ReadPidFromPipe(cmd, pipe_fd);
656 ReadLogFromPipe(pipe_log_fd, PIPE_FD_LEN);
657
658 waitpid(pid, &status, 0);
659 if (errno == ECHILD) {
660 return E_NO_CHILD;
661 }
662 if (!WIFEXITED(status)) {
663 LOGE("Process exits abnormally");
664 return E_ERR;
665 }
666 if (WEXITSTATUS(status) != 0) {
667 LOGE("Process exited with an error");
668 return E_ERR;
669 }
670 }
671 return E_OK;
672 }
673 #endif
674
TraverseDirUevent(const std::string & path,bool flag)675 void TraverseDirUevent(const std::string &path, bool flag)
676 {
677 DIR *dir = opendir(path.c_str());
678 if (dir == nullptr) {
679 return;
680 }
681
682 int dirFd = dirfd(dir);
683 int fd = openat(dirFd, "uevent", O_WRONLY | O_CLOEXEC);
684 if (fd >= 0) {
685 std::string writeStr = "add\n";
686 write(fd, writeStr.c_str(), writeStr.length());
687 (void)close(fd);
688 }
689
690 for (struct dirent *ent = readdir(dir); ent != nullptr; ent = readdir(dir)) {
691 if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
692 continue;
693 }
694
695 if (ent->d_type != DT_DIR && !flag) {
696 continue;
697 }
698
699 TraverseDirUevent(path + "/" + ent->d_name, false);
700 }
701
702 (void)closedir(dir);
703 }
704
IsSameGidUid(const std::string & dir,uid_t uid,gid_t gid)705 int IsSameGidUid(const std::string &dir, uid_t uid, gid_t gid)
706 {
707 struct stat st;
708 if (TEMP_FAILURE_RETRY(lstat(dir.c_str(), &st)) == E_ERR) {
709 LOGE("failed to lstat, errno %{public}d", errno);
710 if (errno == ENOENT) {
711 return E_NON_EXIST;
712 }
713 return E_SYS_KERNEL_ERR;
714 }
715 return (st.st_uid == uid) && (st.st_gid == gid) ? E_OK : E_DIFF_UID_GID;
716 }
717
MoveDataShell(const std::string & from,const std::string & to)718 bool MoveDataShell(const std::string &from, const std::string &to)
719 {
720 LOGI("MoveDataShell start");
721 if (TEMP_FAILURE_RETRY(access(from.c_str(), F_OK)) != 0) {
722 return true;
723 }
724 std::vector<std::string> cmd = {
725 "/system/bin/mv",
726 from,
727 to
728 };
729 std::vector<std::string> out;
730 int32_t err = ForkExec(cmd, &out);
731 if (err != 0) {
732 LOGE("MoveDataShell failed err:%{public}d", err);
733 }
734 return true;
735 }
736
MoveFileManagerData(const std::string & filesPath)737 void MoveFileManagerData(const std::string &filesPath)
738 {
739 std::string docsPath = filesPath + "Docs/";
740 MoveDataShell(filesPath + "Download/", docsPath);
741 MoveDataShell(filesPath + "Documents/", docsPath);
742 MoveDataShell(filesPath + "Desktop/", docsPath);
743 MoveDataShell(filesPath + ".Trash/", docsPath);
744 }
745
ChownRecursion(const std::string & dir,uid_t uid,gid_t gid)746 void ChownRecursion(const std::string &dir, uid_t uid, gid_t gid)
747 {
748 std::vector<std::string> cmd = {
749 "/system/bin/chown",
750 "-R",
751 std::to_string(uid) + ":" + std::to_string(gid),
752 dir
753 };
754 std::vector<std::string> out;
755 int32_t err = ForkExec(cmd, &out);
756 if (err != 0) {
757 LOGE("path: %{public}s chown failed err:%{public}d", cmd.back().c_str(), err);
758 }
759 }
760
IsPathMounted(std::string & path)761 bool IsPathMounted(std::string &path)
762 {
763 if (path.empty()) {
764 return true;
765 }
766 if (path.back() == '/') {
767 path.pop_back();
768 }
769 std::ifstream inputStream(MOUNT_POINT_INFO, std::ios::in);
770 if (!inputStream.is_open()) {
771 LOGE("unable to open /proc/mounts, errno is %{public}d", errno);
772 return false;
773 }
774 std::string tmpLine;
775 while (std::getline(inputStream, tmpLine)) {
776 std::stringstream ss(tmpLine);
777 std::string dst;
778 ss >> dst;
779 ss >> dst;
780 if (path == dst) {
781 inputStream.close();
782 return true;
783 }
784 }
785 inputStream.close();
786 return false;
787 }
788
Split(std::string str,const std::string & pattern)789 std::vector<std::string> Split(std::string str, const std::string &pattern)
790 {
791 std::vector<std::string> result;
792 str += pattern;
793 size_t size = str.size();
794 for (size_t i = 0; i < size; i++) {
795 size_t pos = str.find(pattern, i);
796 if (pos < size) {
797 std::string s = str.substr(i, pos - i);
798 result.push_back(s);
799 i = pos + pattern.size() - 1;
800 }
801 }
802 return result;
803 }
804
DeleteFile(const std::string & path)805 bool DeleteFile(const std::string &path)
806 {
807 DIR *dir;
808 struct dirent *dirinfo;
809 struct stat statbuf;
810 lstat(path.c_str(), &statbuf);
811
812 if (S_ISREG(statbuf.st_mode)) {
813 remove(path.c_str());
814 } else if (S_ISDIR(statbuf.st_mode)) {
815 if ((dir = opendir(path.c_str())) == NULL)
816 return 1;
817 while ((dirinfo = readdir(dir)) != NULL) {
818 std::string filepath;
819 filepath.append(path).append("/").append(dirinfo->d_name);
820 if (strcmp(dirinfo->d_name, ".") == 0 || strcmp(dirinfo->d_name, "..") == 0) {
821 continue;
822 }
823 DeleteFile(filepath);
824 rmdir(filepath.c_str());
825 }
826 closedir(dir);
827 }
828 return 0;
829 }
830
IsTempFolder(const std::string & path,const std::string & sub)831 bool IsTempFolder(const std::string &path, const std::string &sub)
832 {
833 bool result = false;
834 if (IsDir(path)) {
835 std::vector<std::string> paths = Split(path, "/");
836 std::string filePath = paths.back();
837 if (filePath.find(sub) == 0) {
838 result = true;
839 }
840 }
841 return result;
842 }
843
DelTemp(const std::string & path)844 void DelTemp(const std::string &path)
845 {
846 DIR *dir;
847 if (!IsDir(path)) {
848 return;
849 }
850 if ((dir = opendir(path.c_str())) != NULL) {
851 {
852 struct dirent *dirinfo;
853 while ((dirinfo = readdir(dir)) != NULL) {
854 if (strcmp(dirinfo->d_name, ".") == 0 || strcmp(dirinfo->d_name, "..") == 0) {
855 continue;
856 }
857 std::string filePath;
858 filePath.append(path).append("/").append(dirinfo->d_name);
859 if (IsTempFolder(filePath, "simple-mtpfs")) {
860 DeleteFile(filePath.c_str());
861 rmdir(filePath.c_str());
862 }
863 }
864 closedir(dir);
865 }
866 }
867 }
868
CreateFolder(const std::string & path)869 bool CreateFolder(const std::string &path)
870 {
871 if (!access(path.c_str(), F_OK) || path == "") {
872 return true;
873 }
874
875 size_t pos = path.rfind("/");
876 if (pos == std::string::npos) {
877 return false;
878 }
879
880 std::string upperPath = path.substr(0, pos);
881 if (CreateFolder(upperPath)) {
882 if (mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IRWXO)) {
883 if (errno != EEXIST) {
884 return false;
885 }
886 }
887 return true;
888 }
889 return false;
890 }
891
DelFolder(const std::string & path)892 bool DelFolder(const std::string &path)
893 {
894 if (rmdir(path.c_str()) == 0) {
895 return true;
896 }
897 return false;
898 }
899
KillProcess(const std::vector<ProcessInfo> & processList,std::vector<ProcessInfo> & killFailList)900 void KillProcess(const std::vector<ProcessInfo> &processList, std::vector<ProcessInfo> &killFailList)
901 {
902 if (processList.empty()) {
903 return;
904 }
905 for (const auto &item: processList) {
906 int pid = item.pid;
907 LOGI("kill pid %{public}d", pid);
908 kill(pid, SIGKILL);
909 bool isAlive = true;
910 for (int i = 0; i < KILL_RETRY_TIME; i++) {
911 if (!IsProcessAlive(pid)) {
912 LOGI("kill pid %{public}d success.", pid);
913 isAlive = false;
914 break;
915 }
916 usleep(KILL_RETRY_INTERVAL_MS);
917 }
918 if (isAlive) {
919 LOGE("kill pid %{public}d failed.", pid);
920 killFailList.push_back(item);
921 }
922 }
923 }
924
IsProcessAlive(int pid)925 bool IsProcessAlive(int pid)
926 {
927 std::stringstream procPath;
928 procPath << "/proc/" << pid << "/stat";
929 std::ifstream statFile(procPath.str());
930 if (!statFile) {
931 statFile.close();
932 return false;
933 }
934 statFile.close();
935 return true;
936 }
937
ProcessToString(std::vector<ProcessInfo> & processList)938 std::string ProcessToString(std::vector<ProcessInfo> &processList)
939 {
940 if (processList.empty()) {
941 return "";
942 }
943 std::string result;
944 for (auto &iter : processList) {
945 result += std::to_string(iter.pid) + "_" + iter.name + ",";
946 }
947 return result.empty() ? "" : result.substr(0, result.length() -1);
948 }
949
RestoreconDir(const std::string & path)950 bool RestoreconDir(const std::string &path)
951 {
952 #ifdef USE_LIBRESTORECON
953 int err = Restorecon(path.c_str());
954 if (err) {
955 LOGE("failed to restorecon, err:%{public}d", err);
956 return false;
957 }
958 #endif
959 return true;
960 }
961 } // STORAGE_DAEMON
962 } // OHOS
963