1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include "utils/ExecUtils.hpp"
4
5#include "global.hpp"
6
7#include <fcntl.h>
8#include <iostream>
9#include <sys/stat.h>
10#include <unistd.h>
11
12namespace ExecUtils
13{
14 void RedirectLogFd(const std::string &unitBase, const std::string &fileName)
15 {
16 if (unitBase.empty() || fileName.empty())
17 {
18 std::cerr << "RedirectLogFd: unitBase or fileName is empty" << std::endl;
19 exit(status: 1);
20 }
21
22 const std::string log_dir = "/tmp/log/" + unitBase;
23 if (mkdir(pathname: log_dir.c_str(), mode: 0755) == -1 && errno != EEXIST)
24 {
25 std::cerr << "failed to create log directory " << log_dir << std::endl;
26 exit(status: 1);
27 }
28
29 const std::string log_path = "/tmp/log/" + unitBase + "/" + fileName + ".log";
30 const int log_fd = open(path: log_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
31 if (log_fd == -1)
32 {
33 std::cerr << "failed to open log file " << log_path << std::endl;
34 exit(status: 1);
35 }
36
37 dup2(src_fd: log_fd, STDOUT_FILENO);
38 dup2(src_fd: log_fd, STDERR_FILENO);
39 close(fd: log_fd);
40 }
41
42 std::string GetRandomString(size_t length)
43 {
44 static const char alphanum[] = "0123456789"
45 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
46 "abcdefghijklmnopqrstuvwxyz";
47 std::string s;
48 s.reserve(res: length);
49 for (size_t i = 0; i < length; i++)
50 s.push_back(c: alphanum[rand() % (sizeof(alphanum) - 1)]);
51 return s;
52 }
53
54 pid_t DoFork(const std::vector<std::string> &exec, const std::string &token, const std::string &baseId)
55 {
56 int fds[2];
57 if (pipe(pipefd: fds) == -1)
58 {
59 std::cerr << RED("failed to create pipe") << std::endl;
60 return -1;
61 }
62
63 pid_t pid = fork();
64 if (pid == 0)
65 {
66 // child write to pipe a status code, so close the read end
67 close(fd: fds[0]);
68 fcntl(fd: fds[1], F_SETFD, FD_CLOEXEC);
69
70 std::vector<const char *> args;
71 for (const auto &arg : exec)
72 args.push_back(x: arg.c_str());
73 args.push_back(x: nullptr);
74
75 // redirect stdout and stderr to /tmp/log/<baseid>/<pid>.log
76 ExecUtils::RedirectLogFd(unitBase: baseId, fileName: std::to_string(val: getpid()));
77 setenv(name: "MOS_SERVICE_TOKEN", value: token.c_str(), overwrite: true);
78
79 const auto err = execve(path: exec[0].c_str(), argv: (char **) args.data(), envp: environ);
80 if (err == -1)
81 {
82 std::cerr << RED("failed to execute") << " " << exec[0] << ": " << strerror(errno) << std::endl;
83 // write error code to pipe
84 int error_code = errno;
85 write(fd: fds[1], buffer: &error_code, size: sizeof(error_code));
86 close(fd: fds[1]);
87 _exit(status: 1);
88 }
89 // if execve was successful, we should never reach here
90 std::cerr << RED("unreachable code") << std::endl;
91 __builtin_unreachable();
92 return false;
93 }
94
95 // parent process read from pipe to get the status code
96 close(fd: fds[1]);
97
98 int status_code = 0;
99 if (const auto ret = read(fd: fds[0], buffer: &status_code, size: sizeof(status_code)); ret == 0)
100 {
101 // child process has closed the pipe, which means it has executed successfully
102 close(fd: fds[0]);
103 return pid;
104 }
105 else
106 {
107 close(fd: fds[0]);
108 std::cerr << RED("failed to start process") << " " << exec[0] << ": " << strerror(errnum: status_code) << std::to_string(val: status_code) << std::endl;
109 return status_code;
110 }
111 }
112} // namespace ExecUtils
113