66
77#include " linglong/runtime/overlayfs_driver.h"
88
9+ #include " linglong/utils/cmd.h"
910#include " linglong/utils/file.h"
1011
12+ #include < array>
1113#include < fstream>
12- #include < regex>
14+
15+ #include < sys/utsname.h>
1316
1417namespace linglong ::runtime {
18+ namespace {
19+
20+ auto filesystemHasOverlay () noexcept -> bool
21+ {
22+ std::ifstream filesystems (" /proc/filesystems" );
23+ if (!filesystems.is_open ()) {
24+ return false ;
25+ }
26+
27+ std::string line;
28+ while (std::getline (filesystems, line)) {
29+ if (line.find (" overlay" ) != std::string::npos) {
30+ return true ;
31+ }
32+ }
33+
34+ return false ;
35+ }
36+
37+ auto modinfoHasOverlay () noexcept -> bool
38+ {
39+ auto modinfo = utils::Cmd (" modinfo" );
40+ if (!modinfo.exists ()) {
41+ return false ;
42+ }
43+
44+ return modinfo.exec ({ " overlay" }).has_value ();
45+ }
46+
47+ auto overlayModuleExists () noexcept -> bool
48+ {
49+ struct utsname uts{};
50+ if (uname (&uts) != 0 ) {
51+ return false ;
52+ }
53+
54+ const auto modulesRoot = std::filesystem::path (" /lib/modules" ) / uts.release ;
55+ const auto overlayModuleDir = modulesRoot / " kernel" / " fs" / " overlayfs" ;
56+ constexpr std::array<std::string_view, 4 > overlayModules{
57+ " overlay.ko" ,
58+ " overlay.ko.gz" ,
59+ " overlay.ko.xz" ,
60+ " overlay.ko.zst" ,
61+ };
62+
63+ std::error_code ec;
64+ for (const auto module : overlayModules) {
65+ if (std::filesystem::exists (overlayModuleDir / module , ec)) {
66+ return true ;
67+ }
68+ }
69+
70+ for (const auto &index : { " modules.dep" , " modules.builtin" }) {
71+ std::ifstream modulesIndex (modulesRoot / index);
72+ if (!modulesIndex.is_open ()) {
73+ continue ;
74+ }
75+
76+ std::string line;
77+ while (std::getline (modulesIndex, line)) {
78+ if (line.find (" kernel/fs/overlayfs/overlay.ko" ) != std::string::npos) {
79+ return true ;
80+ }
81+ }
82+ }
83+
84+ return false ;
85+ }
86+
87+ auto kernelVersionSupportsUserNamespaceOverlay () noexcept -> bool
88+ {
89+ struct utsname uts{};
90+ if (uname (&uts) != 0 ) {
91+ return false ;
92+ }
93+
94+ int major = 0 ;
95+ int minor = 0 ;
96+ if (std::sscanf (uts.release , " %d.%d" , &major, &minor) == 2 ) {
97+ return major > 5 || (major == 5 && minor >= 11 );
98+ }
99+
100+ return false ;
101+ }
102+
103+ } // namespace
15104
16105auto OverlayFSDriver::create (utils::OverlayMode mode) noexcept -> std::unique_ptr<OverlayFSDriver>
17106{
@@ -34,31 +123,9 @@ auto OverlayFSDriver::detectKernelOverlaySupport() noexcept -> OverlaySupport
34123{
35124 OverlaySupport support{ false , false , false };
36125
37- std::ifstream filesystems (" /proc/filesystems" );
38- if (filesystems.is_open ()) {
39- std::string line;
40- while (std::getline (filesystems, line)) {
41- if (line.find (" overlay" ) != std::string::npos) {
42- support.kernelAvailable = true ;
43- break ;
44- }
45- }
46- }
47-
48- std::ifstream version (" /proc/version" );
49- if (version.is_open ()) {
50- std::string line;
51- std::getline (version, line);
52- std::regex versionRegex (" Linux version (\\ d+)\\ .(\\ d+)" );
53- std::smatch match;
54- if (std::regex_search (line, match, versionRegex) && match.size () > 2 ) {
55- int major = std::stoi (match[1 ]);
56- int minor = std::stoi (match[2 ]);
57- if (major > 5 || (major == 5 && minor >= 11 )) {
58- support.kernelVersionOK = true ;
59- }
60- }
61- }
126+ support.kernelAvailable =
127+ filesystemHasOverlay () || modinfoHasOverlay () || overlayModuleExists ();
128+ support.kernelVersionOK = kernelVersionSupportsUserNamespaceOverlay ();
62129
63130 support.canUseInUserNS = support.kernelAvailable && support.kernelVersionOK ;
64131 return support;
@@ -69,6 +136,40 @@ auto OverlayFSDriver::canUseKernelOverlay() noexcept -> bool
69136 return detectKernelOverlaySupport ().canUseInUserNS ;
70137}
71138
139+ auto OverlayFSDriver::canUseFUSEOverlay () noexcept -> bool
140+ {
141+ return utils::Cmd (" fuse-overlayfs" ).exists ();
142+ }
143+
144+ auto OverlayFSDriver::resolveOverlayMode (utils::OverlayMode mode) noexcept
145+ -> utils::error::Result<utils::OverlayMode>
146+ {
147+ LINGLONG_TRACE (" resolve overlayfs mode" );
148+
149+ switch (mode) {
150+ case utils::OverlayMode::Kernel:
151+ if (canUseKernelOverlay ()) {
152+ return utils::OverlayMode::Kernel;
153+ }
154+ return LINGLONG_ERR (" kernel overlayfs is unavailable" );
155+ case utils::OverlayMode::FUSE :
156+ if (canUseFUSEOverlay ()) {
157+ return utils::OverlayMode::FUSE ;
158+ }
159+ return LINGLONG_ERR (" fuse-overlayfs command is unavailable" );
160+ case utils::OverlayMode::Auto:
161+ if (canUseKernelOverlay ()) {
162+ return utils::OverlayMode::Kernel;
163+ }
164+ if (canUseFUSEOverlay ()) {
165+ return utils::OverlayMode::FUSE ;
166+ }
167+ return LINGLONG_ERR (" no available overlayfs implementation" );
168+ }
169+
170+ return LINGLONG_ERR (" unknown overlayfs mode" );
171+ }
172+
72173auto OverlayFSDriver::modeToString (utils::OverlayMode mode) noexcept -> std::string_view
73174{
74175 return utils::overlayModeToString (mode);
0 commit comments