@@ -8,7 +8,7 @@ Module Name:
88
99Abstract:
1010
11- Entry point for the wsladiag tool, performs WSL runtime initialization and parses list/shell/help .
11+ Entry point for the wsladiag tool. Provides diagnostic commands for WSLA sessions .
1212
1313--*/
1414
@@ -24,32 +24,25 @@ Module Name:
2424
2525using namespace wsl ::shared;
2626namespace wslutil = wsl::windows::common::wslutil;
27+ using wsl::windows::common::Context;
28+ using wsl::windows::common::ExecutionContext;
2729using wsl::windows::common::WSLAProcessLauncher;
2830
29- // Adding a helper to factor error handling between all the arguments .
31+ // Report an operation failure with localized context and HRESULT details .
3032static int ReportError (const std::wstring& context, HRESULT hr)
3133{
32- const std::wstring hrMessage = wslutil::GetErrorString (hr);
33-
34- if (!hrMessage.empty ())
35- {
36- wslutil::PrintMessage (std::format (L" {}: 0x{:08x} - {}" , context, static_cast <uint32_t >(hr), hrMessage), stderr);
37- }
38- else
39- {
40- wslutil::PrintMessage (std::format (L" {}: 0x{:08x}" , context, static_cast <uint32_t >(hr)), stderr);
41- }
42-
34+ auto errorString = wsl::windows::common::wslutil::ErrorCodeToString (hr);
35+ wslutil::PrintMessage (context, stderr);
4336 return 1 ;
4437}
4538
46- // Handler for `wsladiag shell <SessionName> [--verbose] ` command - launches TTY-backed interactive shell .
39+ // Handler for `wsladiag shell <SessionName>` command.
4740static int RunShellCommand (std::wstring_view commandLine)
4841{
4942 std::wstring sessionName;
5043 bool verbose = false ;
5144
52- ArgumentParser parser (std::wstring{commandLine}, L" wsladiag" , 2 , false ); // Skip "wsladiag.exe shell" to parse shell-specific args
45+ ArgumentParser parser (std::wstring{commandLine}, L" wsladiag" , 2 , false );
5346 parser.AddPositionalArgument (sessionName, 0 );
5447 parser.AddArgument (verbose, L" --verbose" , L' v' );
5548
@@ -61,15 +54,6 @@ static int RunShellCommand(std::wstring_view commandLine)
6154 E_INVALIDARG, wsl::shared::Localization::MessageMissingArgument (L" <SessionName>" , L" wsladiag shell" ));
6255 }
6356
64- const auto log = [&](std::wstring_view msg) {
65- if (verbose)
66- {
67- wslutil::PrintMessage (std::wstring (msg), stdout);
68- }
69- };
70-
71- log (std::format (L" [diag] shell='{}'" , sessionName));
72-
7357 wil::com_ptr<IWSLAUserSession> userSession;
7458 THROW_IF_FAILED (CoCreateInstance (__uuidof (WSLAUserSession), nullptr , CLSCTX_LOCAL_SERVER, IID_PPV_ARGS (&userSession)));
7559 wsl::windows::common::security::ConfigureForCOMImpersonation (userSession.get ());
@@ -87,8 +71,6 @@ static int RunShellCommand(std::wstring_view commandLine)
8771 return ReportError (Localization::MessageWslaOpenSessionFailed (sessionName.c_str ()), hr);
8872 }
8973
90- log (L" [diag] OpenSessionByName succeeded" );
91-
9274 // Console size for TTY.
9375 CONSOLE_SCREEN_BUFFER_INFO info{};
9476 THROW_LAST_ERROR_IF (!GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info));
@@ -105,12 +87,9 @@ static int RunShellCommand(std::wstring_view commandLine)
10587 launcher.AddFd (WSLA_PROCESS_FD{.Fd = 1 , .Type = WSLAFdTypeTerminalOutput, .Path = nullptr });
10688 launcher.AddFd (WSLA_PROCESS_FD{.Fd = 2 , .Type = WSLAFdTypeTerminalControl, .Path = nullptr });
10789
108- log (std::format (L" [diag] tty rows={} cols={}" , rows, cols));
10990 launcher.SetTtySize (rows, cols);
11091
111- log (L" [diag] launching shell process..." );
11292 auto process = launcher.Launch (*session);
113- log (L" [diag] shell launched (TTY)" );
11493
11594 auto ttyIn = process.GetStdHandle (0 );
11695 auto ttyOut = process.GetStdHandle (1 );
@@ -129,13 +108,12 @@ static int RunShellCommand(std::wstring_view commandLine)
129108 // Save/restore console state.
130109 DWORD originalInMode{};
131110 DWORD originalOutMode{};
111+ const UINT originalOutCP = GetConsoleOutputCP ();
112+ const UINT originalInCP = GetConsoleCP ();
132113
133114 THROW_LAST_ERROR_IF (!GetConsoleMode (consoleIn, &originalInMode));
134115 THROW_LAST_ERROR_IF (!GetConsoleMode (consoleOut, &originalOutMode));
135116
136- const UINT originalOutCP = GetConsoleOutputCP ();
137- const UINT originalInCP = GetConsoleCP ();
138-
139117 auto restoreConsole = wil::scope_exit_log (WI_DIAGNOSTICS_INFO, [&] {
140118 LOG_IF_WIN32_BOOL_FALSE (SetConsoleMode (consoleIn, originalInMode));
141119 LOG_IF_WIN32_BOOL_FALSE (SetConsoleMode (consoleOut, originalOutMode));
@@ -158,19 +136,13 @@ static int RunShellCommand(std::wstring_view commandLine)
158136
159137 auto exitEvent = wil::unique_event (wil::EventOptions::ManualReset);
160138
161- auto ttyControl = process.GetStdHandle (2 ); // TerminalControl
162- wsl::shared::SocketChannel controlChannel{wil::unique_socket{(SOCKET)ttyControl.release ()}, " TerminalControl" , exitEvent.get ()};
163-
164139 auto updateTerminalSize = [&]() {
165140 CONSOLE_SCREEN_BUFFER_INFOEX infoEx{};
166141 infoEx.cbSize = sizeof (infoEx);
167142 THROW_IF_WIN32_BOOL_FALSE (GetConsoleScreenBufferInfoEx (consoleOut, &infoEx));
168143
169- WSLA_TERMINAL_CHANGED message{};
170- message.Columns = infoEx.srWindow .Right - infoEx.srWindow .Left + 1 ;
171- message.Rows = infoEx.srWindow .Bottom - infoEx.srWindow .Top + 1 ;
172-
173- controlChannel.SendMessage (message);
144+ LOG_IF_FAILED (process.Get ().ResizeTty (
145+ infoEx.srWindow .Bottom - infoEx.srWindow .Top + 1 , infoEx.srWindow .Right - infoEx.srWindow .Left + 1 ));
174146 };
175147
176148 // Start input relay thread to forward console input to TTY
@@ -186,7 +158,7 @@ static int RunShellCommand(std::wstring_view commandLine)
186158 }
187159 });
188160
189- auto joinInput = wil::scope_exit ( [&] {
161+ auto joinInput = wil::scope_exit_log (WI_DIAGNOSTICS_INFO, [&] {
190162 exitEvent.SetEvent ();
191163 if (inputThread.joinable ())
192164 {
@@ -199,22 +171,30 @@ static int RunShellCommand(std::wstring_view commandLine)
199171
200172 process.GetExitEvent ().wait ();
201173
202- auto [ exitCode, signalled] = process.GetExitState ();
174+ auto exitCode = process.GetExitCode ();
203175
204176 std::wstring shellWide (shell.begin (), shell.end ());
205- wslutil::PrintMessage (Localization::MessageWslaShellExited (shellWide.c_str (), exitCode), stdout);
177+ wslutil::PrintMessage (wsl::shared:: Localization::MessageWslaShellExited (shellWide.c_str (), static_cast < int >( exitCode) ), stdout);
206178
207- return 0 ;
179+ return static_cast < int >(exitCode) ;
208180}
209181
182+ // Handler for `wsladiag list` command.
210183static int RunListCommand (std::wstring_view commandLine)
211184{
212185 bool verbose = false ;
213186
214- ArgumentParser parser (std::wstring{commandLine}, L" wsladiag" , 2 , false ); // Skip "wsladiag.exe list" to parse list-specific args
187+ ArgumentParser parser (std::wstring{commandLine}, L" wsladiag" , 2 , false );
215188 parser.AddArgument (verbose, L" --verbose" , L' v' );
216189
217- parser.Parse ();
190+ try
191+ {
192+ parser.Parse ();
193+ }
194+ catch (...)
195+ {
196+ THROW_HR_WITH_USER_ERROR (E_INVALIDARG, wsl::shared::Localization::MessageWsladiagUsage ());
197+ }
218198
219199 wil::com_ptr<IWSLAUserSession> userSession;
220200 THROW_IF_FAILED (CoCreateInstance (__uuidof (WSLAUserSession), nullptr , CLSCTX_LOCAL_SERVER, IID_PPV_ARGS (&userSession)));
@@ -235,7 +215,8 @@ static int RunListCommand(std::wstring_view commandLine)
235215 }
236216
237217 wslutil::PrintMessage (Localization::MessageWslaSessionsFound (sessions.size (), sessions.size () == 1 ? L" " : L" s" ), stdout);
238- // Compute column widths from headers + data.
218+
219+ // Use localized headers
239220 const auto idHeader = Localization::MessageWslaHeaderId ();
240221 const auto pidHeader = Localization::MessageWslaHeaderCreatorPid ();
241222 const auto nameHeader = Localization::MessageWslaHeaderDisplayName ();
@@ -279,7 +260,6 @@ static int RunListCommand(std::wstring_view commandLine)
279260 for (const auto & s : sessions)
280261 {
281262 const wchar_t * displayName = s.DisplayName ? s.DisplayName : L" " ;
282-
283263 wprintf (
284264 L" %-*lu %-*lu %-*ls\n " ,
285265 static_cast <int >(idWidth),
@@ -293,14 +273,15 @@ static int RunListCommand(std::wstring_view commandLine)
293273 return 0 ;
294274}
295275
276+ // Print localized usage message to stderr.
296277static void PrintUsage ()
297278{
298279 wslutil::PrintMessage (Localization::MessageWsladiagUsage (), stderr);
299280}
300281
301282int wsladiag_main (std::wstring_view commandLine)
302283{
303- // Basic initialization that was previously in this function .
284+ // Initialize runtime and COM .
304285 wslutil::ConfigureCrt ();
305286 wslutil::InitializeWil ();
306287
@@ -316,107 +297,75 @@ int wsladiag_main(std::wstring_view commandLine)
316297 THROW_IF_WIN32_ERROR (WSAStartup (MAKEWORD (2 , 2 ), &data));
317298 auto wsaCleanup = wil::scope_exit_log (WI_DIAGNOSTICS_INFO, []() { WSACleanup (); });
318299
319- // Enable contextualized error collection and create an ExecutionContext so
320- // THROW_HR_WITH_USER_ERROR will save a user-visible message.
321- wsl::windows::common::EnableContextualizedErrors (false );
300+ // Parse the top-level verb (list, shell, --help).
301+ ArgumentParser parser (std::wstring{commandLine}, L" wsladiag" , 1 , true );
302+
303+ bool help = false ;
304+ std::wstring verb;
305+
306+ parser.AddPositionalArgument (verb, 0 );
307+ parser.AddArgument (help, L" --help" , L' h' );
322308
323- FILE* warningsFile = nullptr ;
324- const char * disableWarnings = getenv ( " WSL_DISABLE_WARNINGS " );
325- if (disableWarnings == nullptr || strcmp (disableWarnings, " 1 " ) != 0 )
309+ parser. Parse () ;
310+
311+ if (help || verb. empty () )
326312 {
327- warningsFile = stderr;
313+ PrintUsage ();
314+ return 0 ;
328315 }
329316
330- std::optional<wsl::windows::common::ExecutionContext> context;
331- context.emplace (wsl::windows::common::Context::Wsl, warningsFile);
332-
333- int exitCode = 0 ;
334- HRESULT result = S_OK;
317+ if (verb == L" list" )
318+ {
319+ return RunListCommand (commandLine);
320+ }
335321
336- try
322+ if (verb == L" shell " )
337323 {
338- ArgumentParser parser (std::wstring{commandLine}, L" wsladiag" , 1 , true );
324+ return RunShellCommand (commandLine);
325+ }
339326
340- bool help = false ;
341- std::wstring verb;
327+ // Unknown verb - show usage and fail.
328+ wslutil::PrintMessage (Localization::MessageWslaUnknownCommand (verb.c_str ()), stderr);
329+ PrintUsage ();
330+ return 1 ;
331+ }
342332
343- parser.AddPositionalArgument (verb, 0 );
344- parser.AddArgument (help, L" --help" , L' h' );
333+ int wmain (int , wchar_t **)
334+ {
335+ wsl::windows::common::EnableContextualizedErrors (false );
345336
346- parser.Parse (); // Let exceptions propagate to this try/catch
337+ ExecutionContext context{Context::WslaDiag};
338+ int exitCode = 1 ;
339+ HRESULT result = S_OK;
347340
348- if (help || verb.empty ())
349- {
350- PrintUsage ();
351- exitCode = 0 ;
352- }
353- else if (verb == L" list" )
354- {
355- exitCode = RunListCommand (commandLine);
356- }
357- else if (verb == L" shell" )
358- {
359- exitCode = RunShellCommand (commandLine);
360- }
361- else
362- {
363- wslutil::PrintMessage (Localization::MessageWslaUnknownCommand (verb.c_str ()), stderr);
364- PrintUsage ();
365- exitCode = 1 ;
366- }
341+ try
342+ {
343+ exitCode = wsladiag_main (GetCommandLineW ());
367344 }
368345 catch (...)
369346 {
370- // Capture the exception HRESULT and fall through to printing contextualized error.
371347 result = wil::ResultFromCaughtException ();
372- // Default nonzero exit code on failure.
373- exitCode = 1 ;
374348 }
375349
376- // If there was a failure, attempt to print a contextualized error message collected
377- // by the ExecutionContext. Otherwise fall back to the HRESULT -> string path.
378350 if (FAILED (result))
379351 {
380352 try
381353 {
382- std::wstring errorString{};
383- if (context.has_value () && context->ReportedError ().has_value ())
354+ if (auto reported = context.ReportedError ())
384355 {
385- auto strings = wsl::windows::common::wslutil::ErrorToString (context->ReportedError ().value ());
386-
387- // For most errors, show both message and code
388- errorString = wsl::shared::Localization::MessageErrorCode (strings.Message , strings.Code );
389-
390- // Log telemetry for user-visible errors (matches other tools).
391- WSL_LOG (" UserVisibleError" , TraceLoggingValue (strings.Code .c_str (), " ErrorCode" ));
356+ auto strings = wsl::windows::common::wslutil::ErrorToString (*reported);
357+ wslutil::PrintMessage (wsl::shared::Localization::MessageErrorCode (strings.Message , strings.Code ), stderr);
392358 }
393359 else
394360 {
395- // Fallback: show basic HRESULT string.
396- errorString = wslutil::ErrorCodeToString (result);
361+ wslutil::PrintMessage (wslutil::GetErrorString (result), stderr);
397362 }
398-
399- wslutil::PrintMessage (errorString, stderr);
400363 }
401364 catch (...)
402365 {
403366 LOG_CAUGHT_EXCEPTION ();
404367 }
405-
406368 }
407369
408370 return exitCode;
409- }
410-
411- int wmain (int , wchar_t **)
412- {
413- try
414- {
415- return wsladiag_main (GetCommandLineW ());
416- }
417- catch (...)
418- {
419- const auto hr = wil::ResultFromCaughtException ();
420- return ReportError (L" wsladiag failed" , hr);
421- }
422371}
0 commit comments