master
cpp 577 lines 25.4 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 WslCoreConfigInterface.cpp
8
9 Abstract:
10
11 This file contains the WSL Core Config Interface class interface definition.
12
13 --*/
14
15 #include <WslCoreConfigInterface.h>
16 #include "WslCoreConfig.h"
17 #include <helpers.hpp>
18
19 using namespace wsl::shared::string;
20 using namespace wsl::core;
21
22 static_assert(NetworkingConfiguration::None == static_cast<int32_t>(wsl::core::NetworkingMode::None));
23 static_assert(NetworkingConfiguration::Nat == static_cast<int32_t>(wsl::core::NetworkingMode::Nat));
24 static_assert(NetworkingConfiguration::Bridged == static_cast<int32_t>(wsl::core::NetworkingMode::Bridged));
25 static_assert(NetworkingConfiguration::Mirrored == static_cast<int32_t>(wsl::core::NetworkingMode::Mirrored));
26 static_assert(NetworkingConfiguration::Consomme == static_cast<int32_t>(wsl::core::NetworkingMode::Consomme));
27
28 static_assert(MemoryReclaimConfiguration::Disabled == static_cast<int32_t>(wsl::core::MemoryReclaimMode::Disabled));
29 static_assert(MemoryReclaimConfiguration::Gradual == static_cast<int32_t>(wsl::core::MemoryReclaimMode::Gradual));
30 static_assert(MemoryReclaimConfiguration::DropCache == static_cast<int32_t>(wsl::core::MemoryReclaimMode::DropCache));
31
32 struct WslConfig
33 {
34 WslConfig() = default;
35
36 WslConfig(const wchar_t* wslConfigFilePath) :
37 ConfigFilePath(wslConfigFilePath == nullptr ? std::filesystem::path() : wslConfigFilePath), Config(wslConfigFilePath)
38 {
39 }
40
41 std::filesystem::path ConfigFilePath;
42 wsl::core::Config Config;
43 std::wstring IgnoredPortsStr;
44 };
45
46 const wchar_t* GetWslConfigFilePath()
47 {
48 static std::filesystem::path g_wslConfigFilePath;
49 static std::once_flag flag;
50 std::call_once(flag, [&]() { g_wslConfigFilePath = wsl::windows::common::helpers::GetWslConfigPath(nullptr); });
51
52 return g_wslConfigFilePath.c_str();
53 }
54
55 WslConfig_t CreateWslConfig(const wchar_t* wslConfigFilePath)
56 {
57 return new WslConfig(wslConfigFilePath);
58 }
59
60 void FreeWslConfig(WslConfig_t wslConfig)
61 {
62 if (wslConfig)
63 {
64 delete wslConfig;
65 }
66 }
67
68 WslConfigSetting GetWslConfigSetting(WslConfig_t wslConfig, WslConfigEntry wslConfigEntry)
69 {
70 if (wslConfig == nullptr)
71 {
72 return {.ConfigEntry = WslConfigEntry::NoEntry};
73 }
74
75 WslConfigSetting wslConfigSetting{.ConfigEntry = wslConfigEntry};
76 switch (wslConfigEntry)
77 {
78 case NoEntry:
79 // In addition to returning this entry type on error (e.g. invalid WslConfig_t parameter),
80 // the caller can request this entry type returned to initialize an empty WslConfigSetting object.
81 // The caller can then use the returned object in future calls to this function. The intention
82 // of this is an interop scenario where an auto-generated interop layer manages unmanaged memory
83 // (the returned WslConfigSetting object in this case) and is unable or doesn't generate the interop
84 // code to create such an object itself.
85 return wslConfigSetting;
86 case ProcessorCount:
87 static_assert(std::is_same<decltype(wslConfigSetting.Int32Value), decltype(wslConfig->Config.ProcessorCount)>::value);
88 wslConfigSetting.Int32Value = wslConfig->Config.ProcessorCount;
89 break;
90 case MemorySizeBytes:
91 static_assert(std::is_same<decltype(wslConfigSetting.UInt64Value), decltype(wslConfig->Config.MemorySizeBytes)>::value);
92 wslConfigSetting.UInt64Value = wslConfig->Config.MemorySizeBytes;
93 break;
94 case SwapSizeBytes:
95 static_assert(std::is_same<decltype(wslConfigSetting.UInt64Value), decltype(wslConfig->Config.SwapSizeBytes)>::value);
96 wslConfigSetting.UInt64Value = wslConfig->Config.SwapSizeBytes;
97 break;
98 case SwapFilePath:
99 static_assert(std::is_same<decltype(wslConfigSetting.StringValue), decltype(wslConfig->Config.SwapFilePath.c_str())>::value);
100 wslConfigSetting.StringValue = wslConfig->Config.SwapFilePath.c_str();
101 break;
102 case VhdSizeBytes:
103 static_assert(std::is_same<decltype(wslConfigSetting.UInt64Value), decltype(wslConfig->Config.VhdSizeBytes)>::value);
104 wslConfigSetting.UInt64Value = wslConfig->Config.VhdSizeBytes;
105 break;
106 case Networking:
107 wslConfigSetting.NetworkingConfigurationValue = static_cast<NetworkingConfiguration>(wslConfig->Config.NetworkingMode);
108 break;
109 case FirewallEnabled:
110 static_assert(std::is_same<decltype(wslConfigSetting.BoolValue), decltype(wslConfig->Config.FirewallConfig.Enabled())>::value);
111 wslConfigSetting.BoolValue = wslConfig->Config.FirewallConfig.Enabled();
112 break;
113 case IgnoredPorts:
114 {
115 // The IgnoredPorts member is stored as a set of 16-bit unsigned integers.
116 // These are converted back to a string here for the caller to consume.
117 wslConfig->IgnoredPortsStr.clear();
118 std::vector<uint16_t> ignoredPorts{wslConfig->Config.IgnoredPorts.begin(), wslConfig->Config.IgnoredPorts.end()};
119 std::sort(ignoredPorts.begin(), ignoredPorts.end());
120
121 wslConfig->IgnoredPortsStr = Join(ignoredPorts, L',');
122
123 static_assert(std::is_same<decltype(wslConfigSetting.StringValue), decltype(wslConfig->IgnoredPortsStr.c_str())>::value);
124 wslConfigSetting.StringValue = wslConfig->IgnoredPortsStr.c_str();
125 }
126 break;
127 case LocalhostForwardingEnabled:
128 static_assert(std::is_same<decltype(wslConfigSetting.BoolValue), decltype(wslConfig->Config.EnableLocalhostRelay)>::value);
129 wslConfigSetting.BoolValue = wslConfig->Config.EnableLocalhostRelay;
130 break;
131 case HostAddressLoopbackEnabled:
132 static_assert(std::is_same<decltype(wslConfigSetting.BoolValue), decltype(wslConfig->Config.EnableHostAddressLoopback)>::value);
133 wslConfigSetting.BoolValue = wslConfig->Config.EnableHostAddressLoopback;
134 break;
135 case AutoProxyEnabled:
136 static_assert(std::is_same<decltype(wslConfigSetting.BoolValue), decltype(wslConfig->Config.EnableAutoProxy)>::value);
137 wslConfigSetting.BoolValue = wslConfig->Config.EnableAutoProxy;
138 break;
139 case InitialAutoProxyTimeout:
140 static_assert(std::is_same<decltype(wslConfigSetting.Int32Value), decltype(wslConfig->Config.InitialAutoProxyTimeout)>::value);
141 wslConfigSetting.Int32Value = wslConfig->Config.InitialAutoProxyTimeout;
142 break;
143 case DNSProxyEnabled:
144 static_assert(std::is_same<decltype(wslConfigSetting.BoolValue), decltype(wslConfig->Config.EnableDnsProxy)>::value);
145 wslConfigSetting.BoolValue = wslConfig->Config.EnableDnsProxy;
146 break;
147 case DNSTunnelingEnabled:
148 static_assert(std::is_same<decltype(wslConfigSetting.BoolValue), decltype(wslConfig->Config.EnableDnsTunneling)>::value);
149 wslConfigSetting.BoolValue = wslConfig->Config.EnableDnsTunneling;
150 break;
151 case BestEffortDNSParsingEnabled:
152 static_assert(std::is_same<decltype(wslConfigSetting.BoolValue), decltype(wslConfig->Config.BestEffortDnsParsing)>::value);
153 wslConfigSetting.BoolValue = wslConfig->Config.BestEffortDnsParsing;
154 break;
155 case AutoMemoryReclaim:
156 wslConfigSetting.MemoryReclaimModeValue = static_cast<MemoryReclaimConfiguration>(wslConfig->Config.MemoryReclaim);
157 break;
158 case GUIApplicationsEnabled:
159 static_assert(std::is_same<decltype(wslConfigSetting.BoolValue), decltype(wslConfig->Config.EnableGuiApps)>::value);
160 wslConfigSetting.BoolValue = wslConfig->Config.EnableGuiApps;
161 break;
162 case NestedVirtualizationEnabled:
163 static_assert(std::is_same<decltype(wslConfigSetting.BoolValue), decltype(wslConfig->Config.EnableNestedVirtualization)>::value);
164 wslConfigSetting.BoolValue = wslConfig->Config.EnableNestedVirtualization;
165 break;
166 case SafeModeEnabled:
167 static_assert(std::is_same<decltype(wslConfigSetting.BoolValue), decltype(wslConfig->Config.EnableSafeMode)>::value);
168 wslConfigSetting.BoolValue = wslConfig->Config.EnableSafeMode;
169 break;
170 case SparseVHDEnabled:
171 static_assert(std::is_same<decltype(wslConfigSetting.BoolValue), decltype(wslConfig->Config.EnableSparseVhd)>::value);
172 wslConfigSetting.BoolValue = wslConfig->Config.EnableSparseVhd;
173 break;
174 case VMIdleTimeout:
175 static_assert(std::is_same<decltype(wslConfigSetting.Int32Value), decltype(wslConfig->Config.VmIdleTimeout)>::value);
176 wslConfigSetting.Int32Value = wslConfig->Config.VmIdleTimeout;
177 break;
178 case DebugConsoleEnabled:
179 static_assert(std::is_same<decltype(wslConfigSetting.BoolValue), decltype(wslConfig->Config.EnableDebugConsole)>::value);
180 wslConfigSetting.BoolValue = wslConfig->Config.EnableDebugConsole;
181 break;
182 case HardwarePerformanceCountersEnabled:
183 static_assert(std::is_same<decltype(wslConfigSetting.BoolValue), decltype(wslConfig->Config.EnableHardwarePerformanceCounters)>::value);
184 wslConfigSetting.BoolValue = wslConfig->Config.EnableHardwarePerformanceCounters;
185 break;
186 case KernelPath:
187 static_assert(std::is_same<decltype(wslConfigSetting.StringValue), decltype(wslConfig->Config.KernelPath.c_str())>::value);
188 wslConfigSetting.StringValue = wslConfig->Config.KernelPath.c_str();
189 break;
190 case SystemDistroPath:
191 static_assert(std::is_same<decltype(wslConfigSetting.StringValue), decltype(wslConfig->Config.SystemDistroPath.c_str())>::value);
192 wslConfigSetting.StringValue = wslConfig->Config.SystemDistroPath.c_str();
193 break;
194 case KernelModulesPath:
195 static_assert(std::is_same<decltype(wslConfigSetting.StringValue), decltype(wslConfig->Config.KernelModulesPath.c_str())>::value);
196 wslConfigSetting.StringValue = wslConfig->Config.KernelModulesPath.c_str();
197 break;
198 case InstanceIdleTimeout:
199 static_assert(std::is_same<decltype(wslConfigSetting.Int32Value), decltype(wslConfig->Config.InstanceIdleTimeout)>::value);
200 wslConfigSetting.Int32Value = wslConfig->Config.InstanceIdleTimeout;
201 break;
202 default:
203 FAIL_FAST();
204 }
205
206 return wslConfigSetting;
207 }
208
209 // Template instantiation acts as a type check for the ValueType parameter (e.g. an
210 // implicit assert for newValue and outValue having the same type).
211 template <typename ValueType>
212 unsigned long SetWslConfigSetting(WslConfig_t wslConfig, const char* keyName, ValueType& defaultValue, ValueType& newValue, ValueType& outValue)
213 {
214 ConfigKey configKey(keyName, newValue);
215 const auto removeKey = defaultValue == newValue;
216 const auto result = wslConfig->Config.WriteConfigFile(wslConfig->ConfigFilePath.c_str(), configKey, removeKey);
217 if (result == 0)
218 {
219 outValue = newValue;
220 }
221
222 return result;
223 }
224
225 unsigned long SetWslConfigSetting(WslConfig_t wslConfig, const char* keyName, const wchar_t* defaultValue, const wchar_t* newValue, std::wstring& outValue)
226 {
227 std::wstring newValueStr{newValue};
228 const ConfigKey configKey(keyName, newValueStr);
229 const auto removeKey = wsl::shared::string::IsEqual(defaultValue, newValueStr, true);
230 const auto result = wslConfig->Config.WriteConfigFile(wslConfig->ConfigFilePath.c_str(), configKey, removeKey);
231 if (result == 0)
232 {
233 outValue = std::move(newValueStr);
234 }
235
236 return result;
237 }
238
239 unsigned long SetWslConfigSetting(
240 WslConfig_t wslConfig, const char* keyName, const std::filesystem::path& defaultValue, const wchar_t* newValue, std::filesystem::path& outValue)
241 {
242 // Normalize the path.
243 std::filesystem::path filePath;
244 try
245 {
246 filePath = std::filesystem::path(newValue);
247 }
248 catch (const std::exception&)
249 {
250 return ERROR_INVALID_PARAMETER;
251 }
252
253 // The WSL config file needs to have backslashes escaped for file paths.
254 // Assuming these are valid Windows Paths, replace any backslashes with double backslashes.
255 auto newValueStr = std::regex_replace(filePath.wstring(), std::wregex(L"\\\\"), L"\\\\");
256 const ConfigKey configKey(keyName, newValueStr);
257 const auto removeKey = defaultValue == newValue;
258 const auto result = wslConfig->Config.WriteConfigFile(wslConfig->ConfigFilePath.c_str(), configKey, removeKey);
259 if (result == 0)
260 {
261 outValue = newValue;
262 }
263
264 return result;
265 }
266
267 unsigned long SetWslConfigSetting(
268 WslConfig_t wslConfig, const char* keyName, const MemoryString& defaultValue, const MemoryString& newValue, unsigned __int64& outValue)
269 {
270 const ConfigKey configKey(keyName, newValue);
271 const auto removeKey = defaultValue.m_value == newValue.m_value;
272 const auto result = wslConfig->Config.WriteConfigFile(wslConfig->ConfigFilePath.c_str(), configKey, removeKey);
273 if (result == 0)
274 {
275 outValue = newValue.m_value;
276 }
277
278 return result;
279 }
280
281 unsigned long SetWslConfigSetting(WslConfig_t wslConfig, WslConfigSetting wslConfigSetting)
282 {
283 if (wslConfig == nullptr)
284 {
285 return ERROR_INVALID_PARAMETER;
286 }
287
288 // Create a Config object with the default initialized values.
289 wsl::core::Config defaultConfig(nullptr);
290
291 // The following scope exit is intended to re-initialize/update the Config object after a change is made
292 // upon a successful write to the config file and updating of the corresponding member of the Config object.
293 // Depending on the member and value updated, the value itself or others may change as well.
294 auto initializeConfig = wil::scope_exit([&] { wslConfig->Config.Initialize(); });
295
296 switch (wslConfigSetting.ConfigEntry)
297 {
298 case ProcessorCount:
299 return SetWslConfigSetting(
300 wslConfig, ConfigSetting::Processors, defaultConfig.ProcessorCount, wslConfigSetting.Int32Value, wslConfig->Config.ProcessorCount);
301 case MemorySizeBytes:
302 return SetWslConfigSetting(
303 wslConfig,
304 ConfigSetting::Memory,
305 MemoryString(defaultConfig.MemorySizeBytes),
306 MemoryString(wslConfigSetting.UInt64Value),
307 wslConfig->Config.MemorySizeBytes);
308 case SwapSizeBytes:
309 return SetWslConfigSetting(
310 wslConfig,
311 ConfigSetting::Swap,
312 MemoryString(defaultConfig.SwapSizeBytes),
313 MemoryString(wslConfigSetting.UInt64Value),
314 wslConfig->Config.SwapSizeBytes);
315 case SwapFilePath:
316 {
317 if (wslConfigSetting.StringValue == nullptr)
318 {
319 return ERROR_INVALID_PARAMETER;
320 }
321
322 return SetWslConfigSetting(
323 wslConfig, ConfigSetting::SwapFile, defaultConfig.SwapFilePath, wslConfigSetting.StringValue, wslConfig->Config.SwapFilePath);
324 }
325 case VhdSizeBytes:
326 return SetWslConfigSetting(
327 wslConfig,
328 ConfigSetting::DefaultVhdSize,
329 MemoryString(defaultConfig.VhdSizeBytes),
330 MemoryString(wslConfigSetting.UInt64Value),
331 wslConfig->Config.VhdSizeBytes);
332 case Networking:
333 {
334 wsl::core::NetworkingMode networkingConfiguration{static_cast<wsl::core::NetworkingMode>(wslConfigSetting.NetworkingConfigurationValue)};
335 ConfigKey key({ConfigSetting::NetworkingMode, ConfigSetting::Experimental::NetworkingMode}, wsl::core::NetworkingModes, networkingConfiguration);
336 const auto removeKey = defaultConfig.NetworkingMode == networkingConfiguration;
337 const auto result = wslConfig->Config.WriteConfigFile(wslConfig->ConfigFilePath.c_str(), key, removeKey);
338 if (result == 0)
339 {
340 wslConfig->Config.NetworkingMode = networkingConfiguration;
341 wslConfig->Config.NetworkingModePresence = removeKey ? ConfigKeyPresence::Absent : ConfigKeyPresence::Present;
342 }
343 return result;
344 }
345 case FirewallEnabled:
346 {
347 ConfigKey key({ConfigSetting::Firewall, ConfigSetting::Experimental::Firewall}, wslConfigSetting.BoolValue);
348 const auto removeKey = defaultConfig.FirewallConfig.Enabled() == wslConfigSetting.BoolValue;
349 const auto result = wslConfig->Config.WriteConfigFile(wslConfig->ConfigFilePath.c_str(), key, removeKey);
350 if (result == 0)
351 {
352 if (wslConfigSetting.BoolValue)
353 {
354 wslConfig->Config.FirewallConfig.Enable();
355 }
356 else
357 {
358 wslConfig->Config.FirewallConfig.reset();
359 }
360
361 wslConfig->Config.FirewallConfigPresence = removeKey ? ConfigKeyPresence::Absent : ConfigKeyPresence::Present;
362 }
363
364 return result;
365 }
366 case IgnoredPorts:
367 {
368 if (wslConfigSetting.StringValue == nullptr)
369 {
370 return ERROR_INVALID_PARAMETER;
371 }
372
373 std::string ignoredPortsUtf8;
374 if (FAILED(wil::ResultFromException(
375 [&]() { ignoredPortsUtf8 = wsl::shared::string::WideToMultiByte(wslConfigSetting.StringValue); })))
376 {
377 return ERROR_INVALID_PARAMETER;
378 }
379
380 // IgnoredPorts is unique compared to other settings as it parses a string into a set of 16-bit unsigned integers.
381 // In this case, write out the ignored ports as a string. On success, parse the string into a set of 16-bit unsigned
382 // integers and update the IgnoredPorts member of the Config object.
383 static_assert(std::is_same<decltype(wslConfigSetting.StringValue), decltype(wslConfig->IgnoredPortsStr.c_str())>::value);
384 const auto ignoredPortsKeyName = ConfigSetting::Experimental::IgnoredPorts;
385
386 const std::vector<uint16_t> defaultIgnoredPorts{defaultConfig.IgnoredPorts.begin(), defaultConfig.IgnoredPorts.end()};
387 const std::wstring defaultIgnoredPortsStr = Join(defaultIgnoredPorts, L',');
388
389 const auto result = SetWslConfigSetting(
390 wslConfig, ignoredPortsKeyName, defaultIgnoredPortsStr.c_str(), wslConfigSetting.StringValue, wslConfig->IgnoredPortsStr);
391 if (result == 0)
392 {
393 wslConfig->Config.IgnoredPorts.clear();
394 auto parseIgnoredPorts = [&wslConfig](const char*, const char* value, const wchar_t*, unsigned long) {
395 const auto ignoredPortsVector = Split(std::string{value}, ',');
396 for (const auto& portString : ignoredPortsVector)
397 {
398 int number = 0;
399 if (FAILED(wil::ResultFromException([&]() { number = std::stoi(portString); })) || (number <= 0 || number > USHRT_MAX))
400 {
401 continue;
402 }
403
404 wslConfig->Config.IgnoredPorts.insert(static_cast<uint16_t>(number));
405 }
406 };
407
408 ConfigKey key(ignoredPortsKeyName, std::move(parseIgnoredPorts));
409 key.Parse(ignoredPortsKeyName, ignoredPortsUtf8.c_str(), nullptr, 0);
410 }
411
412 return result;
413 }
414 case LocalhostForwardingEnabled:
415 {
416 static_assert(std::is_same<decltype(wslConfigSetting.BoolValue), decltype(wslConfig->Config.EnableLocalhostRelay)>::value);
417 ConfigKey key(ConfigSetting::LocalhostForwarding, wslConfigSetting.BoolValue);
418 const auto removeKey = defaultConfig.EnableLocalhostRelay == wslConfigSetting.BoolValue;
419 const auto result = wslConfig->Config.WriteConfigFile(wslConfig->ConfigFilePath.c_str(), key, removeKey);
420 if (result == 0)
421 {
422 wslConfig->Config.EnableLocalhostRelay = wslConfigSetting.BoolValue;
423 wslConfig->Config.LocalhostRelayConfigPresence = removeKey ? ConfigKeyPresence::Absent : ConfigKeyPresence::Present;
424 }
425
426 return result;
427 }
428 case HostAddressLoopbackEnabled:
429 return SetWslConfigSetting(
430 wslConfig,
431 ConfigSetting::Experimental::HostAddressLoopback,
432 defaultConfig.EnableHostAddressLoopback,
433 wslConfigSetting.BoolValue,
434 wslConfig->Config.EnableHostAddressLoopback);
435 case AutoProxyEnabled:
436 {
437 static_assert(std::is_same<decltype(wslConfigSetting.BoolValue), decltype(wslConfig->Config.EnableAutoProxy)>::value);
438 ConfigKey key({ConfigSetting::AutoProxy, ConfigSetting::Experimental::AutoProxy}, wslConfigSetting.BoolValue);
439 const auto removeKey = defaultConfig.EnableAutoProxy == wslConfigSetting.BoolValue;
440 const auto result = wslConfig->Config.WriteConfigFile(wslConfig->ConfigFilePath.c_str(), key, removeKey);
441 if (result == 0)
442 {
443 wslConfig->Config.EnableAutoProxy = wslConfigSetting.BoolValue;
444 }
445
446 return result;
447 }
448 case InitialAutoProxyTimeout:
449 return SetWslConfigSetting(
450 wslConfig,
451 ConfigSetting::Experimental::InitialAutoProxyTimeout,
452 defaultConfig.InitialAutoProxyTimeout,
453 wslConfigSetting.Int32Value,
454 wslConfig->Config.InitialAutoProxyTimeout);
455 case DNSProxyEnabled:
456 return SetWslConfigSetting(
457 wslConfig, ConfigSetting::DnsProxy, defaultConfig.EnableDnsProxy, wslConfigSetting.BoolValue, wslConfig->Config.EnableDnsProxy);
458 case DNSTunnelingEnabled:
459 {
460 static_assert(std::is_same<decltype(wslConfigSetting.BoolValue), decltype(wslConfig->Config.EnableDnsTunneling)>::value);
461 ConfigKey key({ConfigSetting::DnsTunneling, ConfigSetting::Experimental::DnsTunneling}, wslConfigSetting.BoolValue);
462 const auto removeKey = defaultConfig.EnableDnsTunneling == wslConfigSetting.BoolValue;
463 const auto result = wslConfig->Config.WriteConfigFile(wslConfig->ConfigFilePath.c_str(), key, removeKey);
464 if (result == 0)
465 {
466 wslConfig->Config.EnableDnsTunneling = wslConfigSetting.BoolValue;
467 wslConfig->Config.DnsTunnelingConfigPresence = removeKey ? ConfigKeyPresence::Absent : ConfigKeyPresence::Present;
468 }
469
470 return result;
471 }
472 case BestEffortDNSParsingEnabled:
473 return SetWslConfigSetting(
474 wslConfig,
475 ConfigSetting::Experimental::BestEffortDnsParsing,
476 defaultConfig.BestEffortDnsParsing,
477 wslConfigSetting.BoolValue,
478 wslConfig->Config.BestEffortDnsParsing);
479 case AutoMemoryReclaim:
480 {
481 wsl::core::MemoryReclaimMode memoryReclaimMode{static_cast<wsl::core::MemoryReclaimMode>(wslConfigSetting.MemoryReclaimModeValue)};
482 ConfigKey key({ConfigSetting::Experimental::AutoMemoryReclaim}, wsl::core::MemoryReclaimModes, memoryReclaimMode);
483 const auto removeKey = defaultConfig.MemoryReclaim == memoryReclaimMode;
484 const auto result = wslConfig->Config.WriteConfigFile(wslConfig->ConfigFilePath.c_str(), key, removeKey);
485 if (result == 0)
486 {
487 wslConfig->Config.MemoryReclaim = memoryReclaimMode;
488 }
489
490 return result;
491 }
492 case GUIApplicationsEnabled:
493 return SetWslConfigSetting(
494 wslConfig, ConfigSetting::GuiApplications, defaultConfig.EnableGuiApps, wslConfigSetting.BoolValue, wslConfig->Config.EnableGuiApps);
495 case NestedVirtualizationEnabled:
496 return SetWslConfigSetting(
497 wslConfig,
498 ConfigSetting::NestedVirtualization,
499 defaultConfig.EnableNestedVirtualization,
500 wslConfigSetting.BoolValue,
501 wslConfig->Config.EnableNestedVirtualization);
502 case SafeModeEnabled:
503 return SetWslConfigSetting(
504 wslConfig, ConfigSetting::SafeMode, defaultConfig.EnableSafeMode, wslConfigSetting.BoolValue, wslConfig->Config.EnableSafeMode);
505 case SparseVHDEnabled:
506 return SetWslConfigSetting(
507 wslConfig,
508 ConfigSetting::Experimental::SparseVhd,
509 defaultConfig.EnableSparseVhd,
510 wslConfigSetting.BoolValue,
511 wslConfig->Config.EnableSparseVhd);
512 case VMIdleTimeout:
513 return SetWslConfigSetting(
514 wslConfig, ConfigSetting::VmIdleTimeout, defaultConfig.VmIdleTimeout, wslConfigSetting.Int32Value, wslConfig->Config.VmIdleTimeout);
515 case DebugConsoleEnabled:
516 return SetWslConfigSetting(
517 wslConfig,
518 ConfigSetting::DebugConsole,
519 defaultConfig.EnableDebugConsole,
520 wslConfigSetting.BoolValue,
521 wslConfig->Config.EnableDebugConsole);
522 case HardwarePerformanceCountersEnabled:
523 return SetWslConfigSetting(
524 wslConfig,
525 ConfigSetting::HardwarePerformanceCounters,
526 defaultConfig.EnableHardwarePerformanceCounters,
527 wslConfigSetting.BoolValue,
528 wslConfig->Config.EnableHardwarePerformanceCounters);
529 case KernelPath:
530 {
531 if (wslConfigSetting.StringValue == nullptr)
532 {
533 return ERROR_INVALID_PARAMETER;
534 }
535
536 return SetWslConfigSetting(
537 wslConfig, ConfigSetting::Kernel, defaultConfig.KernelPath, wslConfigSetting.StringValue, wslConfig->Config.KernelPath);
538 }
539 case SystemDistroPath:
540 {
541 if (wslConfigSetting.StringValue == nullptr)
542 {
543 return ERROR_INVALID_PARAMETER;
544 }
545
546 return SetWslConfigSetting(
547 wslConfig,
548 ConfigSetting::SystemDistro,
549 defaultConfig.SystemDistroPath,
550 wslConfigSetting.StringValue,
551 wslConfig->Config.SystemDistroPath);
552 }
553 case KernelModulesPath:
554 {
555 if (wslConfigSetting.StringValue == nullptr)
556 {
557 return ERROR_INVALID_PARAMETER;
558 }
559
560 return SetWslConfigSetting(
561 wslConfig,
562 ConfigSetting::KernelModules,
563 defaultConfig.KernelModulesPath,
564 wslConfigSetting.StringValue,
565 wslConfig->Config.KernelModulesPath);
566 }
567 case InstanceIdleTimeout:
568 return SetWslConfigSetting(
569 wslConfig,
570 ConfigSetting::InstanceIdleTimeout,
571 defaultConfig.InstanceIdleTimeout,
572 wslConfigSetting.Int32Value,
573 wslConfig->Config.InstanceIdleTimeout);
574 default:
575 FAIL_FAST();
576 }
577 }