FlatImage
A configurable Linux containerization system
Loading...
Searching...
No Matches
controller.hpp
Go to the documentation of this file.
1
8
9#pragma once
10
11#include <cstdint>
12#include <filesystem>
13#include <memory>
14#include <fcntl.h>
15
16#include "../std/expected.hpp"
18#include "filesystem.hpp"
19#include "overlayfs.hpp"
20#include "unionfs.hpp"
21#include "dwarfs.hpp"
22#include "ciopfs.hpp"
23#include "utils.hpp"
24#include "layers.hpp"
25
34
45{
46
47struct Logs
48{
49 fs::path const path_file_dwarfs;
50 fs::path const path_file_ciopfs;
51 fs::path const path_file_overlayfs;
52 fs::path const path_file_unionfs;
53 fs::path const path_file_janitor;
54};
55
56struct Config
57{
58 // Filesystem configuration
59 bool const is_casefold;
60 uint32_t const compression_level;
61 ns_reserved::ns_overlay::OverlayType overlay_type;
62 // Main mount point
63 fs::path const path_dir_mount;
64 // Overlayfs / Unionfs
65 fs::path const path_dir_work;
66 fs::path const path_dir_upper;
67 fs::path const path_dir_layers;
68 // Ciopfs
69 fs::path const path_dir_ciopfs;
70 fs::path const path_bin_janitor;
71 fs::path const path_bin_self;
72 // Extra layers to mount
73 ns_layers::Layers const layers;
74};
75
77{
78 private:
79 Logs const m_logs;
80 fs::path m_path_dir_mount;
81 fs::path m_path_dir_work;
82 std::vector<fs::path> m_vec_path_dir_mountpoints;
83 std::vector<std::unique_ptr<ns_dwarfs::Dwarfs>> m_dwarfs;
84 std::vector<std::unique_ptr<ns_filesystem::Filesystem>> m_filesystems;
85 std::unique_ptr<ns_subprocess::Child> m_child_janitor;
86 ns_layers::Layers const m_layers;
87
88 [[nodiscard]] uint64_t mount_dwarfs(fs::path const& path_dir_mount);
89 void mount_ciopfs(fs::path const& path_dir_lower, fs::path const& path_dir_upper);
90 void mount_unionfs(std::vector<fs::path> const& vec_path_dir_layer
91 , fs::path const& path_dir_data
92 , fs::path const& path_dir_mount
93 );
94 void mount_overlayfs(std::vector<fs::path> const& vec_path_dir_layer
95 , fs::path const& path_dir_data
96 , fs::path const& path_dir_mount
97 , fs::path const& path_dir_workdir
98 );
99 // In case the parent process fails to clean the mountpoints, this child does it
100 [[nodiscard]] Value<void> spawn_janitor(fs::path const& path_bin_janitor, fs::path const& path_file_log);
101
102 public:
103 Controller(Logs const& logs, Config const& config);
104 ~Controller();
105 Controller(Controller const&) = delete;
106 Controller(Controller&&) = delete;
107 Controller& operator=(Controller const&) = delete;
108 Controller& operator=(Controller&&) = delete;
109};
110
116inline Controller::Controller(Logs const& logs , Config const& config)
117 : m_logs(logs)
118 , m_path_dir_mount(config.path_dir_mount)
119 , m_path_dir_work(config.path_dir_work)
120 , m_vec_path_dir_mountpoints()
121 , m_dwarfs()
122 , m_filesystems()
123 , m_child_janitor(nullptr)
124 , m_layers(config.layers)
125{
126 // Mount compressed layers
127 [[maybe_unused]] uint64_t index_fs = mount_dwarfs(config.path_dir_layers);
128 // Use unionfs-fuse
129 if ( config.overlay_type == ns_reserved::ns_overlay::OverlayType::UNIONFS )
130 {
131 logger("D::Overlay type: UNIONFS_FUSE");
132 mount_unionfs(::ns_filesystems::ns_utils::get_mounted_layers(config.path_dir_layers)
133 , config.path_dir_upper
134 , config.path_dir_mount
135 );
136 }
137 // Use fuse-overlayfs
138 else if ( config.overlay_type == ns_reserved::ns_overlay::OverlayType::OVERLAYFS )
139 {
140 logger("D::Overlay type: FUSE_OVERLAYFS");
141 mount_overlayfs(::ns_filesystems::ns_utils::get_mounted_layers(config.path_dir_layers)
142 , config.path_dir_upper
143 , config.path_dir_mount
144 , config.path_dir_work
145 );
146 }
147 else
148 {
149 logger("D::Overlay type: BWRAP");
150 }
151 // Put casefold over overlayfs or unionfs
152 if (config.is_casefold)
153 {
154 if(config.overlay_type == ns_reserved::ns_overlay::OverlayType::BWRAP)
155 {
156 logger("W::casefold cannot be used with bwrap overlays");
157 }
158 else
159 {
160 mount_ciopfs(config.path_dir_mount, config.path_dir_ciopfs);
161 logger("D::casefold is enabled");
162 }
163 }
164 else
165 {
166 logger("D::casefold is disabled");
167 }
168 // Spawn janitor, make it permissive since flatimage works without it
169 spawn_janitor(config.path_bin_janitor, logs.path_file_janitor).discard("E::Could not spawn janitor");
170}
171
177{
178 // Check if janitor is running
179 return_if(not m_child_janitor,,"E::Janitor is not running");
180 // Stop janitor loop
181 m_child_janitor->kill(SIGTERM);
182}
183
192[[nodiscard]] inline Value<void> Controller::spawn_janitor(fs::path const& path_bin_janitor
193 , fs::path const& path_file_log)
194{
195 // Spawn
196 m_child_janitor = ns_subprocess::Subprocess(path_bin_janitor)
197 .with_args(getpid(), path_file_log, this->m_vec_path_dir_mountpoints)
198 .with_log_file(path_file_log)
199 .spawn();
200 // Check if janitor is running
201 return_if(not m_child_janitor, Error("E::Failed to start janitor"));
202 // Check if child is running
203 if(auto pid = m_child_janitor->get_pid().value_or(-1); pid > 0)
204 {
205 logger("D::Spawned janitor with PID '{}'", pid);
206 }
207 else
208 {
209 return Error("E::Failed to fork janitor");
210 }
211 return {};
212}
213
224inline uint64_t Controller::mount_dwarfs(fs::path const& path_dir_mount)
225{
226 // Filesystem index
227 uint64_t index_fs{};
228
229 auto f_mount = [this](fs::path const& _path_file_binary
230 , fs::path const& _path_dir_mount
231 , uint64_t _index_fs
232 , uint64_t _offset
233 , uint64_t _size_fs) -> Value<void>
234 {
235 // Create mountpoint
236 fs::path path_dir_mount_index = _path_dir_mount / std::to_string(_index_fs);
237 Try(fs::create_directories(path_dir_mount_index));
238 // Configure and mount the filesystem
239 // Keep the object alive in the filesystems vector
240 this->m_dwarfs.emplace_back(
241 std::make_unique<ns_dwarfs::Dwarfs>(getpid()
242 , path_dir_mount_index
243 , _path_file_binary
244 , m_logs.path_file_dwarfs
245 , _offset
246 , _size_fs
247 )
248 );
249 // Include current mountpoint in the mountpoints vector
250 m_vec_path_dir_mountpoints.push_back(path_dir_mount_index);
251 return {};
252 };
253
254 // Mount all filesystems (both embedded and external)
255 for (auto const& [path_file_layer, offset, size] : m_layers.get_layers())
256 {
257 logger("D::Mounting layer from '{}' with offset '{}'", path_file_layer.filename(), offset);
258 // Check if filesystem is of type 'DWARFS'
259 continue_if(not ns_dwarfs::is_dwarfs(path_file_layer, offset)
260 , "E::Invalid dwarfs filesystem appended on the image"
261 );
262 // Mount file as a filesystem
263 if (not f_mount(path_file_layer, path_dir_mount, index_fs, offset, size))
264 {
265 logger("E::Failed to mount filesystem at index {}", index_fs);
266 continue;
267 }
268 // Go to next filesystem if exists
269 index_fs += 1;
270 } // for
271
272 return index_fs;
273}
274
282inline void Controller::mount_unionfs(std::vector<fs::path> const& vec_path_dir_layer
283 , fs::path const& path_dir_data
284 , fs::path const& path_dir_mount)
285{
286 m_filesystems.emplace_back(std::make_unique<ns_unionfs::UnionFs>(getpid()
287 , path_dir_mount
288 , path_dir_data
289 , m_logs.path_file_unionfs
290 , vec_path_dir_layer
291 ));
292 m_vec_path_dir_mountpoints.push_back(path_dir_mount);
293}
294
303inline void Controller::mount_overlayfs(std::vector<fs::path> const& vec_path_dir_layer
304 , fs::path const& path_dir_data
305 , fs::path const& path_dir_mount
306 , fs::path const& path_dir_workdir)
307{
308 m_filesystems.emplace_back(std::make_unique<ns_overlayfs::Overlayfs>(getpid()
309 , path_dir_mount
310 , path_dir_data
311 , path_dir_workdir
312 , m_logs.path_file_overlayfs
313 , vec_path_dir_layer
314 ));
315 m_vec_path_dir_mountpoints.push_back(path_dir_mount);
316}
317
324inline void Controller::mount_ciopfs(fs::path const& path_dir_lower, fs::path const& path_dir_upper)
325{
326 m_filesystems.emplace_back(std::make_unique<ns_ciopfs::Ciopfs>(getpid()
327 , path_dir_lower
328 , path_dir_upper
329 , m_logs.path_file_ciopfs
330 ));
331 m_vec_path_dir_mountpoints.push_back(path_dir_upper);
332}
333
334} // namespace ns_filesystems::ns_controller
335
336/* vim: set expandtab fdm=marker ts=2 sw=2 tw=100 et :*/
Case-insensitive filesystem management using CIOPFS.
Controller(Logs const &logs, Config const &config)
Construct a new Controller:: Controller object.
~Controller()
Destroy the Controller:: Controller object and stops the janitor if it is running.
Manages external DwarFS layer files and directories for the filesystem controller.
Definition layers.hpp:60
std::unique_ptr< Child > spawn()
Spawns (forks) the child process and begins execution.
Subprocess & with_log_file(std::filesystem::path const &path)
Configures logging output for child process stdout/stderr.
Subprocess & with_args(Args &&... args)
Arguments forwarded as the process' arguments.
Manage dwarfs filesystems.
Enhanced error handling framework built on std::expected.
The base class for filesystems.
Layer management for DwarFS filesystems.
#define logger(fmt,...)
Compile-time log level dispatch macro with automatic location capture.
Definition log.hpp:682
Filesystem stack orchestration and management.
bool is_dwarfs(fs::path const &path_file_dwarfs, uint64_t offset=0)
Checks if the filesystem is a Dwarfs filesystem with a given offset.
Definition dwarfs.hpp:114
std::vector< fs::path > get_mounted_layers(fs::path const &path_dir_layers)
Get a path for each layer directory.
Definition utils.hpp:164
Manages the overlay reserved space.
Manages the fuse-overlayfs filesystem.
Enhanced expected type with integrated logging capabilities.
Definition expected.hpp:44
Manages unionfs filesystems.
Filesystem utilities for managing instances and layers.