master
c 406 lines 9.07 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 interop.c
8
9 Abstract:
10
11 This file is the interop test for WSL2.
12
13 --*/
14
15 #include "lxtcommon.h"
16 #include "unittests.h"
17 #include <unistd.h>
18 #include <sys/types.h>
19 #include <sys/wait.h>
20 #include <pty.h>
21 #include <poll.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26
27 #define LXT_NAME "interop"
28
29 #define BUF_SIZE 1024
30 #define LARGE_MESSAGE_SIZE (4096)
31 #define PIPE_READ_END 0
32 #define PIPE_WRITE_END 1
33 #define CMD_NT_BINARY "/mnt/c/Windows/System32/cmd.exe"
34 #define CMD_SYMLINK "/tmp/cmd"
35 #define HELLO_WORLD_STR "hello world"
36
37 int BasicBasicTests(PLXT_ARGS Args);
38
39 int InteropWithPtyTest(PLXT_ARGS Args);
40
41 int InteropWithPipesTest(PLXT_ARGS Args);
42
43 //
44 // Global constants
45 //
46
47 static const LXT_VARIATION g_LxtVariations[] = {
48 {"Interop Test with pipes", InteropWithPipesTest},
49 /* {"Interop Test with pty", InteropWithPtyTest}, */
50 {"Basic interop tests", BasicBasicTests}};
51
52 int InteropTestEntry(int Argc, char* Argv[])
53
54 /*++
55 --*/
56
57 {
58
59 LXT_ARGS Args;
60 int Result;
61
62 LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
63 LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
64
65 ErrorExit:
66 LxtUninitialize();
67 return !LXT_SUCCESS(Result);
68 }
69
70 int readStringFrom(int fd, char* buffer, int buf_size)
71
72 /*++
73
74 Routine Description:
75
76 Reads characters from given file descriptor until either we reach EOF
77 or reach the buffer limit.
78 This function adds the '\0' character at the end of the string.
79
80 Arguments:
81
82 fd : the file descriptor from which data should be read.
83 buffer: the buffer into which data should be read.
84 buf_size: Size of the 'buffer'. This function will read at max
85 (buf_size - 1) bytes from fd. Last byte is reserved to write '\0'
86 character.
87
88 Return Value:
89
90 Returns number of bytes read.
91
92 --*/
93
94 {
95 if (fd < 0 || !buffer || (buf_size <= 0))
96 {
97 return 0;
98 }
99
100 char* readptr = buffer;
101 int remaining = buf_size - 1;
102 int rc = 0;
103 while (remaining > 0 && (rc = read(fd, readptr, remaining)) > 0)
104 {
105 readptr += rc;
106 remaining -= rc;
107 }
108 *readptr = 0;
109 // exclude '\0' from length
110 return (buf_size - remaining - 1);
111 }
112
113 int InteropWithPtyTest(PLXT_ARGS Args)
114
115 /*++
116
117 Routine Description:
118
119 Test for verifying that interop works as expected when the windows executable is started
120 inside a pseudoterminal.
121
122 Arguments:
123
124 Args - standard arguments provided to every test.
125
126 Return Value:
127
128 Returns 0 on success, -1 on failure.
129
130 --*/
131
132 {
133 int Result;
134 int status;
135 int childpid;
136 int master_fd = -1;
137 char buf[BUF_SIZE];
138
139 LxtCheckErrno((childpid = forkpty(&master_fd, NULL, NULL, NULL)));
140 if (childpid == 0)
141 {
142 // child
143 LxtCheckErrno(execl("/mnt/c/Windows/System32/cmd.exe", "cmd.exe", "/c", "echo", HELLO_WORLD_STR, (char*)NULL));
144 }
145 else
146 {
147 // parent
148
149 readStringFrom(master_fd, buf, sizeof(buf));
150
151 // output generated by echo command should match exactly with the
152 // expected string (along with the CRLF and quotation marks)
153 LxtCheckStringEqual(
154 buf,
155 "\"" HELLO_WORLD_STR
156 "\""
157 "\r\n");
158
159 // make sure child exits normally
160 LxtCheckErrno(waitpid(childpid, &status, 0));
161 LxtCheckResult(WIFEXITED(status));
162 Result = LXT_RESULT_SUCCESS;
163 }
164
165 ErrorExit:
166 if (master_fd != -1)
167 {
168 LxtClose(master_fd);
169 }
170 if (childpid == 0)
171 {
172 _exit(Result);
173 }
174 return Result;
175 }
176
177 int InteropWithPipesTest(PLXT_ARGS Args)
178
179 /*++
180
181 Routine Description:
182
183 Test for verifying that interop works as expected when stdout of the windows executable is redirected.
184
185 Arguments:
186
187 Args - standard arguments provided to every test.
188
189 Return Value:
190
191 Returns 0 on success, -1 on failure.
192
193 --*/
194
195 {
196
197 int Result;
198 int status;
199 int childpid;
200 int child_out_pipe[2];
201 char buf[BUF_SIZE];
202
203 // Pipe to which child's stdout is redirected
204 LxtCheckErrno(pipe(child_out_pipe));
205
206 LxtCheckErrno(childpid = fork());
207 if (childpid == 0)
208 {
209 // child
210 LxtCheckErrno(dup2(child_out_pipe[PIPE_WRITE_END], STDOUT_FILENO));
211 LxtClose(child_out_pipe[PIPE_READ_END]);
212 child_out_pipe[PIPE_READ_END] = -1;
213 LxtClose(child_out_pipe[PIPE_WRITE_END]);
214 child_out_pipe[PIPE_WRITE_END] = -1;
215 // execute a windows executable
216 LxtCheckErrno(execl("/mnt/c/Windows/System32/cmd.exe", "cmd.exe", "/c", "echo", HELLO_WORLD_STR, (char*)NULL));
217 }
218 else
219 {
220 // parent
221
222 LxtClose(child_out_pipe[PIPE_WRITE_END]);
223 child_out_pipe[PIPE_WRITE_END] = -1;
224
225 readStringFrom(child_out_pipe[PIPE_READ_END], buf, sizeof(buf));
226
227 // output generated by echo command should match exactly with the
228 // expected string (along with the CRLF and quotation marks)
229 LxtCheckStringEqual(
230 buf,
231 "\"" HELLO_WORLD_STR
232 "\""
233 "\r\n");
234
235 // make sure child exits normally
236 LxtCheckErrno(waitpid(childpid, &status, 0));
237 LxtCheckResult(WIFEXITED(status));
238 Result = LXT_RESULT_SUCCESS;
239 }
240
241 ErrorExit:
242 if (child_out_pipe[PIPE_READ_END] != -1)
243 {
244 LxtClose(child_out_pipe[PIPE_READ_END]);
245 }
246 if (child_out_pipe[PIPE_WRITE_END] != -1)
247 {
248 LxtClose(child_out_pipe[PIPE_WRITE_END]);
249 }
250 if (childpid == 0)
251 {
252 _exit(Result);
253 }
254 return Result;
255 }
256
257 int BasicBasicTests(PLXT_ARGS Args)
258 /*++
259
260 Routine Description:
261
262 WSL interop tests from version 1 ported for WSL2.
263 These tests call some standard windows commands/executables in different ways and make sure
264 that interop is working as expected.
265
266 Arguments:
267
268 Args - standard arguments provided to every test.
269
270 Return Value:
271
272 Returns 0 on success, -1 on failure.
273
274 --*/
275
276 {
277 int ChildPid;
278 char* ExecArgs[5];
279 int ExitStatus;
280 char* LargeArgument;
281 int Result = LXT_RESULT_FAILURE;
282
283 memset(ExecArgs, 0, sizeof(ExecArgs));
284 LargeArgument = NULL;
285
286 //
287 // Try to launch an invalid NT binary.
288 //
289
290 LxtCheckResult(ChildPid = fork());
291 if (ChildPid == 0)
292 {
293 ExecArgs[0] = "/init";
294 ExecArgs[1] = "invalid_binary_name";
295 LxtCheckErrnoFailure(LxtExecve(ExecArgs[0], ExecArgs, NULL), ENOENT);
296 //
297 // The parent waits for the child to exit successfully.
298 //
299 }
300 else
301 {
302 wait(&ExitStatus);
303 LxtCheckTrue(WIFEXITED(ExitStatus));
304 }
305
306 //
307 // Launch the cmd.exe NT binary.
308 //
309
310 LxtCheckResult(ChildPid = fork());
311 if (ChildPid == 0)
312 {
313 ExecArgs[0] = CMD_NT_BINARY;
314 ExecArgs[1] = "/c";
315 ExecArgs[2] = "exit 0";
316 LxtCheckErrno(LxtExecve(ExecArgs[0], ExecArgs, NULL));
317
318 //
319 // The parent waits for the child to exit successfully.
320 //
321 }
322 else
323 {
324 LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
325 }
326
327 LxtCheckResult(ChildPid = fork());
328 if (ChildPid == 0)
329 {
330 ExecArgs[0] = CMD_NT_BINARY;
331 ExecArgs[1] = "/c";
332 ExecArgs[2] = "exit 1";
333 LxtCheckErrno(LxtExecve(ExecArgs[0], ExecArgs, NULL));
334
335 //
336 // The parent waits for the child to exit successfully.
337 //
338 }
339 else
340 {
341 LxtCheckResult(LxtWaitPidPoll(ChildPid, 1 << 8));
342 }
343
344 //
345 // Launch cmd.exe with a very long command line.
346 //
347
348 LargeArgument = LxtAlloc(LARGE_MESSAGE_SIZE);
349 if (LargeArgument == NULL)
350 {
351 goto ErrorExit;
352 }
353
354 memset(LargeArgument, 'a', LARGE_MESSAGE_SIZE);
355 LargeArgument[LARGE_MESSAGE_SIZE - 1] = '\0';
356 LxtCheckResult(ChildPid = fork());
357 if (ChildPid == 0)
358 {
359 ExecArgs[0] = CMD_NT_BINARY;
360 ExecArgs[1] = "/c";
361 ExecArgs[2] = "echo";
362 ExecArgs[3] = LargeArgument;
363 LxtCheckErrno(LxtExecve(ExecArgs[0], ExecArgs, NULL));
364
365 //
366 // The parent waits for the child to exit successfully.
367 //
368 }
369 else
370 {
371 LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
372 }
373
374 //
375 // Launch cmd.exe through a symlink.
376 //
377
378 LxtCheckErrno(symlink(CMD_NT_BINARY, CMD_SYMLINK));
379 LxtCheckResult(ChildPid = fork());
380 if (ChildPid == 0)
381 {
382 ExecArgs[0] = CMD_SYMLINK;
383 ExecArgs[1] = "/c";
384 ExecArgs[2] = "exit 0";
385 LxtCheckErrno(LxtExecve(ExecArgs[0], ExecArgs, NULL));
386
387 //
388 // The parent waits for the child to exit successfully.
389 //
390 }
391 else
392 {
393 LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
394 }
395
396 ErrorExit:
397 if (ChildPid > 0)
398 {
399 unlink(CMD_SYMLINK);
400 }
401 if (ChildPid == 0)
402 {
403 _exit(Result);
404 }
405 return Result;
406 }