master
h 349 lines 10.3 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 util.h
8
9 Abstract:
10
11 This file contains utility function declarations.
12
13 --*/
14
15 #pragma once
16
17 #include <sys/socket.h>
18 #include <linux/vm_sockets.h>
19 #include <lxwil.h>
20 #include <array>
21 #include <gsl/gsl>
22 #include <gslhelpers.h>
23 #include <chrono>
24 #include <functional>
25 #include <optional>
26 #include <thread>
27 #include <map>
28 #include <future>
29 #include <filesystem>
30 #include <vector>
31 #include <source_location>
32 #include "lxinitshared.h"
33 #include "lxdef.h"
34 #include "common.h"
35
36 namespace wsl::shared {
37 class SocketChannel;
38 class Transaction;
39 } // namespace wsl::shared
40
41 namespace wsl::linux {
42 struct WslDistributionConfig;
43 }
44
45 #define CGROUP_MOUNTPOINT "/sys/fs/cgroup"
46 #define CGROUP2_DEVICE "cgroup2"
47 #define WSL_USER_CGROUP_PATH CGROUP_MOUNTPOINT "/wsl-user"
48 #define WSL_USER_SYSTEMD_CGROUP_DIR "/systemd"
49 #define WSL_USER_NON_SYSTEMD_CGROUP_DIR "/non-systemd"
50 #define WSL_USER_NON_DISTRO_CGROUP_PATH WSL_USER_CGROUP_PATH "/non-distro"
51 #define MOUNT_COMMAND "/bin/mount"
52 #define MOUNT_FSTAB_ARG "-a"
53 #define MOUNT_INTERNAL_ONLY_ARG "-i"
54 #define MOUNT_OPTIONS_ARG "-o"
55 #define MOUNT_TYPES_ARG "-t"
56
57 #define LDCONFIG_COMMAND "/sbin/ldconfig"
58
59 #define PLAN9_ANAME_OPTION "aname="
60 #define PLAN9_ANAME_DRVFS PLAN9_ANAME_OPTION LX_INIT_UTILITY_VM_DRVFS_SHARE_NAME
61 #define PLAN9_ANAME_DRVFS_LENGTH (sizeof(PLAN9_ANAME_DRVFS) - 1)
62 #define PLAN9_ANAME_OPTION_SEP ';'
63 #define PLAN9_ANAME_PATH_OPTION "path="
64 #define PLAN9_ANAME_PATH_OPTION_LENGTH (sizeof(PLAN9_ANAME_PATH_OPTION) - 1)
65 #define PLAN9_UNC_PREFIX "\\\\"
66 #define PLAN9_UNC_TRANSLATED_PREFIX "UNC\\"
67 #define PLAN9_UNC_TRANSLATED_PREFIX_LENGTH (sizeof(PLAN9_UNC_TRANSLATED_PREFIX) - 1)
68
69 #define PLAN9_FS_TYPE "9p"
70 #define VIRTIO_FS_TYPE "virtiofs"
71
72 #define PATH_SEP '/'
73 #define PATH_SEP_NT '\\'
74 #define DRIVE_SEP_NT ':'
75
76 #define WSL_DISTRO_NAME_ENV "WSL_DISTRO_NAME"
77 #define WSL_INTEROP_ENV "WSL_INTEROP"
78 #define WSL_DRVFS_ELEVATED_ENV "WSL_DRVFS_ELEVATED"
79 #define WSL_FEATURE_FLAGS_ENV "WSL_FEATURE_FLAGS"
80 #define WSL_INTEROP_SOCKET "interop"
81 #define WSL_INTEROP_SOCKET_FORMAT "{}/{}_{}"
82 #define WSL_TEMP_FOLDER RUN_FOLDER "/WSL"
83 #define WSL_TEMP_FOLDER_MODE 0777
84 #define WSL_INIT_INTEROP_SOCKET WSL_TEMP_FOLDER "/1_" WSL_INTEROP_SOCKET
85
86 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
87
88 constexpr auto c_defaultRetryPeriod = std::chrono::milliseconds{10};
89 constexpr auto c_defaultRetryTimeout = std::chrono::seconds{15};
90
91 class InteropServer
92 {
93 public:
94 InteropServer() = default;
95 ~InteropServer();
96 InteropServer(const InteropServer&) = delete;
97 InteropServer& operator=(const InteropServer&) = delete;
98
99 InteropServer(InteropServer&& other) noexcept :
100 m_InteropSocketPath(std::move(other.m_InteropSocketPath)), m_InteropSocket(std::move(other.m_InteropSocket))
101 {
102 }
103
104 int Create();
105
106 wil::unique_fd Accept() const;
107
108 int Socket() const
109 {
110 return m_InteropSocket.get();
111 }
112
113 const char* Path() const
114 {
115 return m_InteropSocketPath.c_str();
116 }
117
118 void Reset();
119
120 private:
121 std::string m_InteropSocketPath{};
122 wil::unique_fd m_InteropSocket;
123 };
124
125 int UtilAcceptVsock(int SocketFd, sockaddr_vm Address, int Timeout = -1, int SocketFlags = SOCK_CLOEXEC);
126
127 int UtilBindVsockAnyPort(struct sockaddr_vm* SocketAddress, int Type);
128
129 size_t UtilCanonicalisePathSeparator(char* Path, char Separator);
130
131 void UtilCanonicalisePathSeparator(std::string& Path, char Separator);
132
133 wil::unique_fd UtilConnectToInteropServer(std::optional<pid_t> Pid = {});
134
135 wil::unique_fd UtilConnectUnix(const char* Path);
136
137 wil::unique_fd UtilConnectVsock(
138 unsigned int Port, bool CloseOnExec, std::optional<int> SocketBuffer = {}, const std::source_location& Source = std::source_location::current()) noexcept;
139
140 // Needs to be declared before UtilCreateChildProcess().
141 void UtilSetThreadName(const char* Name);
142
143 void UtilTryMoveSelfToDistroCgroup(const std::string& CgroupPath, bool IsSystemd, const std::string& LogSubject);
144
145 template <typename TMethod>
146 int UtilCreateChildProcess(const char* ChildName, TMethod&& ChildFunction, std::optional<int> CloneFlags = {}, std::optional<std::string> CgroupPath = {})
147
148 /*++
149
150 Routine Description:
151
152 This routine create child process to run the specified function.
153
154 Arguments:
155
156 ChildName - Supplies the child thread name.
157
158 ChildFunction - Supplies a function to be executed in the child process.
159
160 CloneFlags - Supplies an optional value containing flags to use for the clone syscall.
161 If no flags are specified, fork is used instead.
162
163 CgroupPath - Supplies an optional value containing the path of the cgroup to try move the child process into.
164
165 Return Value:
166
167 The pid of the child process on success, -1 on failure. The child process does not return.
168
169 --*/
170
171 {
172 int ChildPid;
173
174 if (CloneFlags)
175 {
176 ChildPid = CLONE(CloneFlags.value());
177 }
178 else
179 {
180 ChildPid = fork();
181 }
182
183 if (ChildPid < 0)
184 {
185 LOG_ERROR("{} for {} failed {}", CloneFlags ? "clone" : "fork", ChildName, errno);
186 return -1;
187 }
188 else if (ChildPid > 0)
189 {
190 return ChildPid;
191 }
192
193 if (CgroupPath.has_value())
194 {
195 UtilTryMoveSelfToDistroCgroup(CgroupPath.value(), false, ChildName);
196 }
197
198 try
199 {
200 UtilSetThreadName(ChildName);
201 ChildFunction();
202 }
203 CATCH_LOG()
204
205 _exit(1);
206 }
207
208 int UtilCreateProcessAndWait(
209 const char* File, const char* const Argv[], int* Status = nullptr, const std::map<std::string, std::string>& Env = {}, bool DetachTerminal = false);
210
211 template <typename TMethod>
212 void UtilCreateWorkerThread(const char* Name, TMethod&& ThreadFunction)
213 {
214 std::promise<void> Promise;
215 std::thread([ThreadFunction = std::move(ThreadFunction), &Promise, Name]() mutable {
216 try
217 {
218 UtilSetThreadName(Name);
219
220 int Result = unshare(CLONE_FS);
221 Promise.set_value();
222 THROW_LAST_ERROR_IF(Result < 0);
223
224 ThreadFunction();
225 }
226 CATCH_LOG()
227 }).detach();
228
229 // Wait for the thread to unshare the filesystem so the next call to setns can succeed.
230 Promise.get_future().wait();
231 }
232
233 int UtilExecCommandLine(const char* CommandLine, std::string* Output = nullptr, int ExpectedStatus = 0, bool PrintError = true);
234
235 std::string UtilFindMount(const char* MountInfoFile, const char* Path, bool WinPath, size_t* PrefixLength);
236
237 std::optional<std::string> UtilGetEnv(const char* Name, char* Environment);
238
239 std::string UtilGetEnvironmentVariable(const char* Name);
240
241 int UtilGetFeatureFlags();
242
243 void UtilSetFeatureFlags(int FeatureFlags, bool UpdateEnv = true);
244
245 std::optional<LX_MINI_INIT_NETWORKING_MODE> UtilGetNetworkingMode(void);
246
247 pid_t UtilGetPpid(pid_t Pid);
248
249 std::string UtilGetVmId(void);
250
251 void UtilInitGroups(const char* User, gid_t Gid);
252
253 void UtilInitializeMessageBuffer(std::vector<gsl::byte>& Buffer);
254
255 bool UtilIsAbsoluteWindowsPath(const char* Path);
256
257 size_t UtilIsPathPrefix(const char* Path, const char* Prefix, bool WinPath);
258
259 bool UtilIsUtilityVm(void);
260
261 int UtilListenVsockAnyPort(struct sockaddr_vm* Address, int Backlog, bool CloseOnExec = true);
262
263 int UtilMkdir(const char* Path, mode_t Mode);
264
265 int UtilMkdirPath(const char* Path, mode_t Mode, bool SkipLast = false);
266
267 int UtilMountFile(const char* Source, const char* Destination);
268
269 int UtilMount(const char* Source, const char* Target, const char* Type, unsigned long MountFlags, const char* Options, std::optional<std::chrono::seconds> TimeoutSeconds = {});
270
271 int UtilMountOverlayFs(const char* Target, const char* Lower, unsigned long MountFlags = 0, std::optional<std::chrono::seconds> TimeoutSeconds = {});
272
273 int UtilOpenMountNamespace(void);
274
275 int UtilParseCgroupsLine(char* Line, char** SubsystemName, bool* Enabled);
276
277 std::string UtilParsePlan9MountSource(std::string_view MountOptions);
278
279 std::vector<char> UtilParseWslEnv(char* NtEnvironment);
280
281 int UtilProcessChildExitCode(int Status, const char* Name, int ExpectedStatus = 0, bool PrintError = true);
282
283 ssize_t UtilRead(int Fd, void* Buffer, size_t BufferSize, int Timeout = -1);
284
285 ssize_t UtilReadBuffer(int Fd, std::vector<gsl::byte>& Buffer, int Timeout = -1);
286
287 std::string UtilReadFile(FILE* File);
288
289 std::vector<gsl::byte> UtilReadFileRaw(const char* Path, size_t MaxSize);
290
291 std::pair<std::optional<std::string>, std::optional<std::string>> UtilReadFlavorAndVersion(const char* Path);
292
293 ssize_t UtilReadMessageLxBus(int MessageFd, std::vector<gsl::byte>& Buffer, bool ShutdownOnDisconnect);
294
295 int UtilRestoreBlockedSignals();
296
297 int UtilSaveBlockedSignals(const sigset_t& NewMask);
298
299 int UtilSaveSignalHandlers(struct sigaction* SavedSignalActions);
300
301 int UtilSetSignalHandlers(struct sigaction* SavedSignalActions, bool Ignore);
302
303 void UtilSocketShutdown(int Fd, int How);
304
305 bool UtilSizeTAdd(size_t Left, size_t Right, size_t* Out);
306
307 std::string_view UtilStringNextToken(std::string_view& View, std::string_view Separators);
308
309 std::string_view UtilStringNextToken(std::string_view& View, char Separator);
310
311 std::optional<std::string> UtilTranslatePathList(char* PathList, bool IsNtPathList);
312
313 std::string UtilWinPathTranslate(const char* Path, bool Reverse);
314
315 std::string UtilWinPathTranslateInternal(const char* Path, bool Reverse);
316
317 ssize_t UtilWriteBuffer(int Fd, gsl::span<const gsl::byte> Buffer);
318
319 ssize_t UtilWriteBuffer(int Fd, const void* Buffer, size_t BufferSize);
320
321 ssize_t UtilWriteStringView(int Fd, std::string_view StringView);
322
323 std::wstring UtilReadFileContentW(std::string_view path);
324
325 std::string UtilReadFileContent(std::string_view path);
326
327 // Holds the hv_pci swiotlb pool the WSL kernel reserved at boot and published
328 // under /sys/bus/vmbus/drivers/hv_pci/swiotlb_{base,size}. Both fields are zero
329 // when running on a kernel that does not publish these files.
330 struct HvPciSwiotlbPool
331 {
332 uint64_t Base = 0;
333 uint64_t Size = 0;
334 };
335
336 HvPciSwiotlbPool UtilReadHvPciSwiotlbPool();
337
338 uint16_t UtilWinAfToLinuxAf(uint16_t AddressFamily);
339
340 int WriteToFile(const char* Path, const char* Content, int OpenFlags = O_WRONLY | O_CLOEXEC | O_CREAT, int Permissions = 0644);
341
342 // Starts a background thread that performs memory compaction and optional cache reclaim when the VM is idle.
343 void StartMemoryReductionThread(LX_MINI_INIT_MEMORY_RECLAIM_MODE Mode);
344
345 int ProcessCreateProcessMessage(wsl::shared::Transaction& Transaction, gsl::span<gsl::byte> Buffer, const std::optional<std::string>& DistroCgroupPath);
346
347 std::string UtilGetDistroCgroupPath(pid_t DistroInitPid);
348
349 int UtilEnableAllCgroupControllers(const std::string& CgroupPath);