FlatImage
A configurable Linux containerization system
Loading...
Searching...
No Matches
portal_daemon.cpp
Go to the documentation of this file.
1
8
9#include <cerrno>
10#include <chrono>
11#include <cstdlib>
12#include <expected>
13#include <fcntl.h>
14#include <sys/prctl.h>
15#include <sys/wait.h>
16#include <thread>
17#include <string>
18#include <csignal>
19#include <filesystem>
20#include <unistd.h>
21
22#include "../std/expected.hpp"
23#include "../lib/log.hpp"
24#include "../lib/env.hpp"
25#include "../lib/linux/fifo.hpp"
28#include "../macro.hpp"
29#include "config.hpp"
30#include "child.hpp"
31
32extern char** environ;
33
34namespace fs = std::filesystem;
37
38// https://stackoverflow.com/questions/24931456/how-does-sig-atomic-t-actually-work
39// https://en.cppreference.com/w/cpp/utility/program/sig_atomic_t.html
40// https://man7.org/linux/man-pages/man7/signal-safety.7.html
41// https://www.cs.wm.edu/~smherwig/courses/csci415-common/signals/sig_atomic/index.html
42volatile std::sig_atomic_t G_CONTINUE = 1;
43
51void cleanup([[maybe_unused]] int sig)
52{
53 G_CONTINUE = 0;
54}
55
61int main()
62{
63 // Register cleanup signal handler
64 signal(SIGTERM, cleanup);
65 // Ignore SIGPIPE - when parent dies and pipe readers close, we can still cleanup
66 signal(SIGPIPE, SIG_IGN);
67
68 auto __expected_fn = [](auto&& e){ logger("E::{}", e.error()); return EXIT_FAILURE; };
69 // Notify
70 logger("D::Started host daemon");
71
72 // Retrieve daemon configuration from environment variables or command-line arguments
73 std::string daemon_cfg_str = Pop(ns_env::get_expected("FIM_DAEMON_CFG"));
74 std::string daemon_log_str = Pop(ns_env::get_expected("FIM_DAEMON_LOG"));
75
76 // Parse arguments
77 auto args_cfg = Pop(ns_daemon::deserialize(daemon_cfg_str));
78 auto args_log = Pop(ns_daemon::ns_log::deserialize(daemon_log_str));
79
80 // Configure logger file
81 ns_log::set_sink_file(args_log.get_path_file_parent());
82 logger("D::Initialized portal daemon in {} mode", args_cfg.get_mode().lower());
83
84 // Create a fifo to receive commands from
85 fs::path path_fifo_in = Pop(ns_linux::ns_fifo::create(args_cfg.get_path_fifo_listen()));
86 int fd_fifo = ::open(path_fifo_in.c_str(), O_RDONLY | O_NONBLOCK);
87 return_if(fd_fifo < 0
88 , EXIT_FAILURE
89 , "E::Could not open file '{}': {}", path_fifo_in, strerror(errno)
90 );
91 logger("D::Listening fifo {}", path_fifo_in);
92
93 // Create dummy writter to keep fifo open
94 [[maybe_unused]] int fd_dummy = ::open(path_fifo_in.c_str(), O_WRONLY);
95 return_if(fd_dummy < 0
96 , EXIT_FAILURE
97 , "E::Could not open dummy writer in '{}', {}", path_fifo_in, strerror(errno)
98 );
99
100 // Get reference pid to the main flatimage program
101 pid_t pid_reference = args_cfg.get_pid_reference();
102
103 // ::read is non-blocking due to O_NONBLOCK, but make sure that any other
104 // operation that might hang do not leave the daemon running after the parent
105 // dies
106 [[maybe_unused]] auto thread_sig = std::jthread([pid_reference,pid=getpid()]
107 {
108 while(kill(pid_reference, 0) == 0)
109 {
110 std::this_thread::sleep_for(std::chrono::milliseconds{100});
111 }
112 kill(pid, SIGTERM);
113 });
114
115 // Recover messages
116 for(char buffer[16384]; G_CONTINUE;)
117 {
118 ssize_t bytes_read = ::read(fd_fifo, &buffer, SIZE_BUFFER_READ);
119 // Check if the read was success full, should try again, or stop
120 // == 0 -> EOF
121 // < 0 -> error (possible retry, because of non-blocking operation)
122 // > 0 -> Possibly valid data to parse
123 if (bytes_read == 0)
124 {
125 break;
126 }
127 else if (bytes_read < 0)
128 {
129 if (errno == EAGAIN or errno == EWOULDBLOCK)
130 {
131 std::this_thread::sleep_for(std::chrono::milliseconds{100});
132 continue;
133 }
134 else
135 {
136 break;
137 }
138 }
139 // Create a safe view over read data
140 std::string_view msg{buffer, static_cast<size_t>(bytes_read)};
141 logger("D::Recovered message: {}", msg);
142 // Validate and deserialize message
143 auto message = ns_message::deserialize(msg);
144 continue_if(not message, "E::Could not parse message: {}", message.error());
145 // Spawn child
146 if(pid_t pid = fork(); pid < 0)
147 {
148 logger("E::Could not fork child");
149 }
150 else if (pid == 0)
151 {
152 ns_portal::ns_child::spawn(args_log, message.value()).discard("C::Could not spawn grandchild");
153 _exit(0);
154 }
155 } // for
156
157 logger("D::Portal daemon shutdown, G_CONTINUE={}", G_CONTINUE);
158
159 close(fd_dummy);
160 close(fd_fifo);
161
162 return EXIT_SUCCESS;
163}
164
165/* vim: set expandtab fdm=marker ts=2 sw=2 tw=100 et :*/
Defines a class that manages FlatImage's portal configuration.
Enhanced error handling framework built on std::expected.
constexpr auto __expected_fn
Lambda helper for Pop macro error returns.
Definition expected.hpp:147
Linux FIFO related operation wrappers.
Value< fs::path > create(fs::path const &path_file_fifo)
Create a fifo object.
Definition fifo.hpp:34
void cleanup(int sig)
Signal handler for parent process exit detection.
Definition janitor.cpp:36
A library for manipulating environment variables.
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.
Value< Logs > deserialize(std::string_view str_raw_json) noexcept
Deserializes a json string into a Logs class.
Definition daemon.hpp:100
Portal daemon configuration and management.
Value< Daemon > deserialize(std::string_view str_raw_json) noexcept
Deserializes a json string into a Daemon class.
Definition daemon.hpp:186
Portal IPC message serialization and deserialization.
Value< Message > deserialize(std::string_view str_raw_json) noexcept
Deserializes a json string into a Message class.
Definition message.hpp:104
Value< std::string > get_expected(std::string_view name)
Get the value of an environment variable.
Definition env.hpp:65
void set_sink_file(fs::path const &path_file_sink)
Sets the sink file of the logger.
Definition log.hpp:359
Value< void > spawn(std::vector< std::string > const &vec_argv, ns_db::ns_portal::ns_message::Message const &message)
Forks a child process and waits for it to complete.
Definition child.hpp:79
Spawns a child process and connects its I/O to pipes.
Constants for portal configuration.
void cleanup(int sig)
Signal handler for daemon cleanup.
int main()
Entry point for the portal daemon.