1 /*
2 * Copyright (c) 2022-2023 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 "b_process/b_process.h"
17
18 #include <algorithm>
19 #include <cstddef>
20 #include <cstdio>
21 #include <functional>
22 #include <memory>
23 #include <regex>
24 #include <string_view>
25 #include <sys/wait.h>
26 #include <tuple>
27 #include <unistd.h>
28
29 #include "b_error/b_error.h"
30 #include "b_process/b_guard_signal.h"
31 #include "errors.h"
32 #include "filemgmt_libhilog.h"
33 #include "securec.h"
34 #include "unique_fd.h"
35
36 namespace OHOS::FileManagement::Backup {
37 using namespace std;
38
WaitForChild(pid_t pid,unique_ptr<FILE,function<void (FILE *)>> pipeStream,function<bool (string_view)> DetectFatalLog)39 static tuple<bool, ErrCode> WaitForChild(pid_t pid,
40 unique_ptr<FILE, function<void(FILE *)>> pipeStream,
41 function<bool(string_view)> DetectFatalLog)
42 {
43 const int BUF_LEN = 1024;
44 auto buf = make_unique<char[]>(BUF_LEN);
45 int status = 0;
46
47 do {
48 regex reg("^\\W*$");
49 while ((void)memset_s(buf.get(), BUF_LEN, 0, BUF_LEN),
50 fgets(buf.get(), BUF_LEN - 1, pipeStream.get()) != nullptr) {
51 if (regex_match(buf.get(), reg)) {
52 continue;
53 }
54 HILOGE("child process output error: %{public}s", buf.get());
55 if (DetectFatalLog && DetectFatalLog(string_view(buf.get()))) {
56 return {true, EPERM};
57 }
58 }
59
60 if (waitpid(pid, &status, 0) == -1) {
61 throw BError(BError::Codes::UTILS_INVAL_PROCESS_ARG, generic_category().message(errno));
62 } else if (WIFEXITED(status)) {
63 return {false, WEXITSTATUS(status)};
64 } else if (WIFSIGNALED(status)) {
65 // 因某种信号中断获取状态
66 // 异常机制存在问题,导致应用在正常的错误下Crash。为确保测试顺利展开,此处暂时屏蔽崩溃错误。
67 HILOGE("some fatal errors occurred, child process is killed by a signal.");
68 return {true, EPERM};
69 }
70 } while (!WIFEXITED(status) && !WIFSIGNALED(status));
71
72 HILOGE("If you look at me, there are some fatal errors occurred!!!");
73 return {true, EPERM};
74 }
75
ExecuteCmd(vector<string_view> argvSv,function<bool (string_view)> DetectFatalLog)76 tuple<bool, ErrCode> BProcess::ExecuteCmd(vector<string_view> argvSv, function<bool(string_view)> DetectFatalLog)
77 {
78 vector<const char *> argv;
79 auto getStringViewData = [](const auto &arg) { return arg.data(); };
80 transform(argvSv.begin(), argvSv.end(), back_inserter(argv), getStringViewData);
81 argv.push_back(nullptr);
82
83 // 临时将SIGCHLD恢复成默认值,从而能够从作为僵尸进程的子进程中获得返回值
84 BGuardSignal guard(SIGCHLD);
85
86 int pipeFd[2];
87 if (pipe(pipeFd) < 0) {
88 throw BError(BError::Codes::UTILS_INTERRUPTED_PROCESS, generic_category().message(errno));
89 }
90
91 pid_t pid = 0;
92 if ((pid = fork()) == 0) {
93 close(STDIN_FILENO);
94 close(STDOUT_FILENO);
95 close(pipeFd[0]);
96 UniqueFd fd(pipeFd[1]);
97 if (dup2(pipeFd[1], STDERR_FILENO) == -1) {
98 throw BError(BError::Codes::UTILS_INTERRUPTED_PROCESS, generic_category().message(errno));
99 }
100 exit((execvp(argv[0], const_cast<char **>(argv.data())) == -1) ? errno : 0);
101 }
102
103 UniqueFd fd(pipeFd[0]);
104 close(pipeFd[1]);
105 if (pid == -1) {
106 throw BError(BError::Codes::UTILS_INVAL_PROCESS_ARG, generic_category().message(errno));
107 }
108 unique_ptr<FILE, function<void(FILE *)>> pipeStream {fdopen(pipeFd[0], "r"), fclose};
109 if (!pipeStream) {
110 throw BError(errno);
111 }
112 fd.Release();
113
114 return WaitForChild(pid, move(pipeStream), DetectFatalLog);
115 }
116 } // namespace OHOS::FileManagement::Backup