xref: /openbmc/phosphor-bmc-code-mgmt/common/src/utils.cpp (revision c538727d70f3673771f18e559d7ecab203abf6d3)
1 #include "common/include/utils.hpp"
2 
3 #include <phosphor-logging/lg2.hpp>
4 
5 PHOSPHOR_LOG2_USING;
6 
asyncSystem(sdbusplus::async::context & ctx,const std::string & cmd,std::optional<std::reference_wrapper<std::string>> result)7 sdbusplus::async::task<bool> asyncSystem(
8     sdbusplus::async::context& ctx, const std::string& cmd,
9     std::optional<std::reference_wrapper<std::string>> result)
10 {
11     int exitPipefd[2];
12     int resultPipefd[2];
13 
14     if (pipe(exitPipefd) == -1 || (result && pipe(resultPipefd) == -1))
15     {
16         error("Failed to create pipe for command: {CMD}", "CMD", cmd);
17         co_return false;
18     }
19 
20     pid_t pid = fork();
21     if (pid == 0)
22     {
23         close(exitPipefd[0]);
24 
25         if (result)
26         {
27             close(resultPipefd[0]);
28             dup2(resultPipefd[1], STDOUT_FILENO);
29             dup2(resultPipefd[1], STDERR_FILENO);
30             close(resultPipefd[1]);
31         }
32 
33         int exitCode = std::system(cmd.c_str());
34         ssize_t status = write(exitPipefd[1], &exitCode, sizeof(exitCode));
35 
36         close(exitPipefd[1]);
37         _exit((status == sizeof(exitCode)) ? 0 : 1);
38     }
39     else if (pid > 0)
40     {
41         close(exitPipefd[1]);
42 
43         if (result)
44         {
45             close(resultPipefd[1]);
46         }
47 
48         auto fdio =
49             std::make_unique<sdbusplus::async::fdio>(ctx, exitPipefd[0]);
50 
51         if (!fdio)
52         {
53             error("Failed to create fdio for command: {CMD}", "CMD", cmd);
54             close(exitPipefd[0]);
55             co_return false;
56         }
57 
58         co_await fdio->next();
59 
60         if (result)
61         {
62             auto& resStr = result->get();
63             resStr.clear();
64             char buffer[1024];
65             ssize_t n;
66             while ((n = read(resultPipefd[0], buffer, sizeof(buffer))) > 0)
67             {
68                 resStr.append(buffer, n);
69             }
70             close(resultPipefd[0]);
71         }
72 
73         int exitCode = -1;
74         ssize_t bytesRead = read(exitPipefd[0], &exitCode, sizeof(exitCode));
75         close(exitPipefd[0]);
76 
77         if (bytesRead != sizeof(exitCode))
78         {
79             error("Failed to read exit code from command {CMD}", "CMD", cmd);
80             co_return false;
81         }
82 
83         int status;
84         if (waitpid(pid, &status, 0) < 0)
85         {
86             error("waitpid failed for PID {PID} for command {CMD}", "PID", pid,
87                   "CMD", cmd);
88             co_return false;
89         }
90 
91         if (exitCode != 0)
92         {
93             error("Command {CMD} exited with code {CODE}", "CMD", cmd, "CODE",
94                   exitCode);
95             co_return false;
96         }
97 
98         debug("{CMD} executed successfully", "CMD", cmd);
99 
100         co_return true;
101     }
102     else
103     {
104         error("Fork failed for command: {CMD}", "CMD", cmd);
105         close(exitPipefd[0]);
106         close(exitPipefd[1]);
107         if (result)
108         {
109             close(resultPipefd[0]);
110             close(resultPipefd[1]);
111         }
112         co_return false;
113     }
114 }
115