FlatImage
A configurable Linux containerization system
Loading...
Searching...
No Matches
portal_dispatcher.cpp
Go to the documentation of this file.
1
8
9#include <chrono>
10#include <csignal>
11#include <cstdlib>
12#include <expected>
13#include <fcntl.h>
14#include <filesystem>
15#include <sys/prctl.h>
16#include <sys/stat.h>
17#include <sys/types.h>
18#include <sys/wait.h>
19#include <unistd.h>
20
21#include "../macro.hpp"
22#include "../std/expected.hpp"
23#include "../std/filesystem.hpp"
24#include "../lib/env.hpp"
25#include "../lib/log.hpp"
26#include "../lib/linux.hpp"
27#include "../lib/linux/fifo.hpp"
28#include "../lib/linux/fd.hpp"
31#include "config.hpp"
32
33namespace fs = std::filesystem;
36
37extern char** environ;
38std::optional<pid_t> opt_child = std::nullopt;
39
45void signal_handler(int sig)
46{
47 if(opt_child)
48 {
49 kill(opt_child.value(), sig);
50 }
51}
52
60{
61 signal(SIGABRT, signal_handler);
62 signal(SIGTERM, signal_handler);
63 signal(SIGINT, signal_handler);
64 signal(SIGCONT, signal_handler);
65 signal(SIGHUP, signal_handler);
66 signal(SIGIO, signal_handler);
67 signal(SIGIOT, signal_handler);
68 signal(SIGPIPE, signal_handler);
69 signal(SIGPOLL, signal_handler);
70 signal(SIGQUIT, signal_handler);
71 signal(SIGURG, signal_handler);
72 signal(SIGUSR1, signal_handler);
73 signal(SIGUSR2, signal_handler);
74 signal(SIGVTALRM, signal_handler);
75}
76
84{
85 Pop(ns_linux::ns_fifo::create(msg.get_stdin()));
86 Pop(ns_linux::ns_fifo::create(msg.get_stdout()));
87 Pop(ns_linux::ns_fifo::create(msg.get_stderr()));
88 Pop(ns_linux::ns_fifo::create(msg.get_exit()));
89 Pop(ns_linux::ns_fifo::create(msg.get_pid()));
90 return {};
91}
92
100[[nodiscard]] Value<void> send_message(ns_message::Message const& message, fs::path const& path_fifo_daemon)
101{
102 logger("D::Sending message through pipe: {}", path_fifo_daemon);
103 // Serialize to json string
104 std::string data = Pop(ns_message::serialize(message));
105 logger("D::{}", data);
106 // Write to fifo
107 ssize_t size_writen = ns_linux::open_write_with_timeout(path_fifo_daemon
108 , std::chrono::seconds(SECONDS_TIMEOUT)
109 , std::span(data.c_str(), data.length())
110 );
111 // Check for errors
112 return (static_cast<size_t>(size_writen) != data.length())?
113 Error("E::Could not write data to daemon({}): {}", size_writen, strerror(errno))
114 : Value<void>{};
115}
116
125[[nodiscard]] Value<int> process_wait(ns_message::Message const& message)
126{
127 // Child pid received through a fifo
128 pid_t pid_child;
129 ssize_t bytes_read = ns_linux::open_read_with_timeout(message.get_pid()
130 , std::chrono::seconds(SECONDS_TIMEOUT)
131 , std::span<pid_t>(&pid_child, 1)
132 );
133 return_if(bytes_read != sizeof(pid_child), Error("E::{}", strerror(errno)));
134 // Check if PID is valid
135 return_if(pid_child < 0, Error("E::Could not start PID, program not found?"));
136 // Forward signal to pid
137 opt_child = pid_child;
138 logger("D::Child pid: {}", pid_child);
139 // Connect to stdin, stdout, and stderr with fifos and wait for them to exit
140 {
141 std::jthread thread_stdin([pid_child, message]
142 {
143 ns_linux::ns_fd::redirect_fd_to_file(pid_child, STDIN_FILENO, message.get_stdin()).discard();
144 });
145 std::jthread thread_stdout([pid_child, message]
146 {
147 ns_linux::ns_fd::redirect_file_to_fd(pid_child, message.get_stdout(), STDOUT_FILENO).discard();
148 });
149 std::jthread thread_stderr([pid_child, message]
150 {
151 ns_linux::ns_fd::redirect_file_to_fd(pid_child, message.get_stderr(), STDERR_FILENO).discard();
152 });
153 logger("D::Connected to stdin/stdout/stderr fifos");
154 }
155 // Open exit code fifo and retrieve the exit code of the requested process
156 int code_exit{};
157 int bytes_exit = ns_linux::open_read_with_timeout(message.get_exit().c_str()
158 , std::chrono::seconds{SECONDS_TIMEOUT}
159 , std::span<int>(&code_exit, 1)
160 );
161 return_if(bytes_exit != sizeof(code_exit), Error("E::Incorrect number of bytes '{}' read", bytes_exit));
162 return code_exit;
163}
164
173[[nodiscard]] Value<int> process_request(fs::path const& path_fifo_daemon
174 , fs::path const& path_dir_fifo
175 , std::vector<std::string> const& cmd
176 )
177{
178 using namespace std::chrono_literals;
179 // Get environment
180 auto environment = std::ranges::subrange(environ, std::unreachable_sentinel)
181 | std::views::take_while([](char* p) { return p != nullptr; })
182 | std::ranges::to<std::vector<std::string>>();
183 // Build message with dispatcher PID
184 auto message = ns_message::Message(getpid(), cmd, path_dir_fifo, environment);
185 // Create fifos and build message
186 Pop(fifo_create(message));
187 // Create parent directories
188 Pop(ns_fs::create_directories(message.get_exit().parent_path()));
189 // Send message to daemon
190 Pop(send_message(message, path_fifo_daemon));
191 // Wait for child process and retrieve exit code
192 return Pop(process_wait(message));
193}
194
202int main(int argc, char** argv)
203{
204 auto __expected_fn = [](auto&& e){ logger("E::{}", e.error()); return EXIT_FAILURE; };
205 // Set log level
206 ns_log::set_level(ns_env::exists("FIM_DEBUG", "1")? ns_log::Level::DEBUG : ns_log::Level::ERROR);
207 // Collect arguments
208 std::vector<std::string> args(argv+1, argv+argc);
209 // No arguments for portal
210 return_if(args.empty(), EXIT_FAILURE, "E::No arguments for dispatcher");
211 // De-serialize FIM_DISPATCHER_CFG
212 ns_dispatcher::Dispatcher arg_cfg = Pop(
213 ns_dispatcher::deserialize(Pop(ns_env::get_expected("FIM_DISPATCHER_CFG")))
214 );
215 // Set log file
216 ns_log::set_sink_file(arg_cfg.get_path_file_log());
217 // Register signals
219 // Request process from daemon
220 return Pop(process_request(arg_cfg.get_path_fifo_daemon()
221 , arg_cfg.get_path_dir_fifo()
222 , args
223 ) , "E::Failure to dispatch process request");
224}
225
226/* vim: set expandtab fdm=marker ts=2 sw=2 tw=100 et :*/
Defines a class that manages FlatImage's portal dispatcher configuration.
Enhanced error handling framework built on std::expected.
constexpr auto __expected_fn
Lambda helper for Pop macro error returns.
Definition expected.hpp:147
File descriptor redirection helpers.
Value< void > redirect_file_to_fd(pid_t ppid, fs::path const &path_file, int fd_dst)
Redirects the output of a file to a file descriptor.
Definition fd.hpp:93
Value< void > redirect_fd_to_file(pid_t ppid, int fd_src, fs::path const &path_file)
Redirects the output of a file descriptor to a file.
Definition fd.hpp:120
Linux FIFO related operation wrappers.
Value< fs::path > create(fs::path const &path_file_fifo)
Create a fifo object.
Definition fifo.hpp:34
A library for manipulating environment variables.
A library with helpers for linux operations.
A library for file logging.
#define logger(fmt,...)
Compile-time log level dispatch macro with automatic location capture.
Definition log.hpp:682
Simplified macros for common control flow patterns with optional logging.
Defines a class that manages portal daemon message serialization/deserialization.
Portal command dispatcher configuration.
Value< Dispatcher > deserialize(std::string_view str_raw_json) noexcept
Deserializes a json string into a Dispatcher class.
Portal IPC message serialization and deserialization.
Value< std::string > serialize(Message const &message) noexcept
Serializes a Message class into a json string.
Definition message.hpp:129
Value< std::string > get_expected(std::string_view name)
Get the value of an environment variable.
Definition env.hpp:65
bool exists(std::string_view name, std::string_view value)
Checks if variable exists and equals value.
Definition env.hpp:82
Value< fs::path > create_directories(fs::path const &p)
Creates directories recursively.
ssize_t open_write_with_timeout(fs::path const &path_file_src, std::chrono::milliseconds const &timeout, std::span< Data > buf)
Opens and writes to the given input file.
Definition linux.hpp:226
ssize_t open_read_with_timeout(fs::path const &path_file_src, std::chrono::milliseconds const &timeout, std::span< Data > buf)
Opens and reads from the given input file.
Definition linux.hpp:205
void set_level(Level level)
Sets the logging verbosity (CRITICAL,ERROR,INFO,DEBUG)
Definition log.hpp:339
void set_sink_file(fs::path const &path_file_sink)
Sets the sink file of the logger.
Definition log.hpp:359
Constants for portal configuration.
int main()
Entry point for the portal daemon.
Value< void > send_message(ns_message::Message const &message, fs::path const &path_fifo_daemon)
Sends a message to the portal daemon.
Value< int > process_request(fs::path const &path_fifo_daemon, fs::path const &path_dir_fifo, std::vector< std::string > const &cmd)
Sends a request to the daemon to create a new process.
void signal_handler(int sig)
Forwards received signal to requested child process.
void register_signals()
Registers signal handlers for dispatcher cleanup.
Value< int > process_wait(ns_message::Message const &message)
Waits for the requested process to finish.
Value< void > fifo_create(ns_message::Message const &msg)
Creates FIFOs for child process I/O.
Filesystem helpers.
Enhanced expected type with integrated logging capabilities.
Definition expected.hpp:44