master
c 394 lines 9.85 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 tty.c
8
9 Abstract:
10
11 This file contains unit tests for the /dev/tty0
12
13 --*/
14
15 #include "lxtcommon.h"
16 #include "unittests.h"
17 #include <unistd.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <poll.h>
23 #include <linux/kd.h>
24 #include <linux/vt.h>
25 #include <termios.h>
26 #include <sys/ioctl.h>
27
28 #define LXT_NAME "tty"
29
30 #define LXT_MANUAL_OUTPUT "ttyOutput.txt"
31
32 #define LXT_NON_DEFAULT_MODE (S_IFCHR | 0111)
33
34 #define LXT_NON_DEFAULT_ID 255
35
36 LXT_VARIATION_HANDLER TestDevTty0Ioctl;
37
38 LXT_VARIATION_HANDLER TestDevTtyIoctl;
39
40 LXT_VARIATION_HANDLER TestDevTtyStat;
41
42 LXT_VARIATION_HANDLER TestDevTtyOpen;
43
44 LXT_VARIATION_HANDLER TestDevTtySecurity;
45
46 //
47 // TODO: Enable TestDevTty0Ioctl
48 //
49
50 static const LXT_VARIATION g_LxtVariations[] = {
51 // {"Test the implementation of the ioctl(/dev/tty0)", TestDevTty0Ioctl},
52 {"tty stat", TestDevTtyStat},
53 {"tty open", TestDevTtyOpen},
54 {"tty security", TestDevTtySecurity},
55 {"tty ioctl", TestDevTtyIoctl}};
56
57 int TtyTestEntry(int argc, char* argv[])
58 {
59 LXT_ARGS Args;
60 int Result;
61
62 //
63 // Started in a unit test mode.
64 //
65
66 LxtCheckResult(LxtInitialize(argc, argv, &Args, LXT_NAME));
67 LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
68
69 ErrorExit:
70 LxtUninitialize();
71 return !LXT_SUCCESS(Result);
72 }
73
74 int TestDevTty0Ioctl(PLXT_ARGS Args)
75
76 {
77
78 int fd;
79 int err;
80 char path[] = "/dev/tty0";
81 struct vt_stat vt_stat;
82 int vt_index;
83 struct termios termios;
84 int i;
85
86 err = -1;
87 fd = -1;
88
89 //
90 // Open the target.
91 //
92
93 fd = open(path, O_RDWR);
94 if (-1 == fd)
95 {
96 err = errno;
97 LxtLogError("open('%s') failed, %d", path, err);
98 goto exit;
99 }
100
101 //
102 // Test the ioctl(KDSETMODE)
103 //
104
105 err = ioctl(fd, KDSETMODE, KD_TEXT);
106 if (-1 == err)
107 {
108 err = errno;
109 LxtLogError("ioctl('%s', KDSETMODE, KD_TEXT) failed, %d", path, err);
110 goto exit;
111 }
112
113 LxtLogInfo("ioctl('%s', KDSETMODE) -> %d ", path, err);
114
115 //
116 // Test the ioctl(VT_GETSTATE)
117 //
118
119 err = ioctl(fd, VT_GETSTATE, &vt_stat);
120 if (-1 == err)
121 {
122 err = errno;
123 LxtLogError("ioctl('%s', VT_GETSTATE) failed, %d", path, err);
124 goto exit;
125 }
126
127 LxtLogInfo("ioctl('%s', VT_GETSTATE) -> %d ", path, err);
128 LxtLogInfo(" vt_stat.v_active = %d", vt_stat.v_active);
129 LxtLogInfo(" vt_stat.v_signal = %d", vt_stat.v_signal);
130 LxtLogInfo(" vt_stat.v_state = %d", vt_stat.v_state);
131
132 //
133 // Test the activation of the VT#7
134 //
135
136 vt_index = 7;
137
138 err = ioctl(fd, VT_ACTIVATE, vt_index);
139 if (-1 == err)
140 {
141 err = errno;
142 LxtLogError("ioctl('%s', VT_ACTIVATE, %d) failed, %d", path, vt_index, err);
143 goto exit;
144 }
145
146 LxtLogInfo("ioctl('%s', VT_ACTIVATE, %d) -> %d ", path, vt_index, err);
147
148 err = ioctl(fd, VT_WAITACTIVE, vt_index);
149 if (-1 == err)
150 {
151 err = errno;
152 LxtLogError("ioctl('%s', VT_WAITACTIVE, %d) failed, %d", path, vt_index, err);
153 goto exit;
154 }
155
156 LxtLogInfo("ioctl('%s', VT_WAITACTIVE, %d) -> %d ", path, vt_index, err);
157
158 //
159 // Get/set port settings.
160 //
161
162 #if !defined(__amd64__)
163
164 err = ioctl(fd, TCGETS, &termios);
165 if (-1 == err)
166 {
167 err = errno;
168 LxtLogError("ioctl('%s', TCGETS) failed, %d", path, err);
169 goto exit;
170 }
171
172 LxtLogInfo("ioctl('%s', TCGETS) -> %d ", path, err);
173 LxtLogInfo(" termios.c_iflag = %d", termios.c_iflag);
174 LxtLogInfo(" termios.c_oflag = %d", termios.c_oflag);
175 LxtLogInfo(" termios.c_cflag = %d", termios.c_cflag);
176 LxtLogInfo(" termios.c_lflag = %d", termios.c_lflag);
177 LxtLogInfo(" termios.c_line = %d", termios.c_line);
178 for (i = 0; i < NCCS; i++)
179 {
180 LxtLogInfo(" termios.c_cc[%d] = %d", i, termios.c_cc[i]);
181 }
182
183 #endif
184
185 //
186 // Test the ioctl(VT_GETSTATE) after all preparation completed.
187 //
188
189 err = ioctl(fd, VT_GETSTATE, &vt_stat);
190 if (-1 == err)
191 {
192 err = errno;
193 LxtLogError("ioctl('%s', VT_GETSTATE) failed, %d", path, err);
194 goto exit;
195 }
196
197 LxtLogInfo("ioctl('%s', VT_GETSTATE) -> %d ", path, err);
198 LxtLogInfo(" vt_stat.v_active = %d", vt_stat.v_active);
199 LxtLogInfo(" vt_stat.v_signal = %d", vt_stat.v_signal);
200 LxtLogInfo(" vt_stat.v_state = %d", vt_stat.v_state);
201
202 //
203 // Done.
204 // Close the test device handle.
205 //
206
207 close(fd);
208 fd = -1;
209
210 err = 0;
211
212 exit:
213 if (-1 != fd)
214 {
215 close(fd);
216 }
217
218 return err;
219 }
220
221 int TestDevTtyIoctl(PLXT_ARGS Args)
222
223 {
224 int Mode = 0;
225 int Result;
226
227 LxtCheckErrno(ioctl(0, KDGKBTYPE, &Mode));
228 LxtCheckEqual(Mode, KB_101, "%d");
229 LxtCheckErrno(ioctl(0, KDGKBMODE, &Mode));
230 LxtCheckEqual(Mode, K_UNICODE, "%d");
231 LxtCheckErrno(ioctl(0, KDSKBMODE, Mode));
232
233 Result = LXT_RESULT_SUCCESS;
234
235 ErrorExit:
236 return Result;
237 }
238
239 int TestDevTtyStat(PLXT_ARGS Args)
240
241 {
242
243 int Index;
244 int Result;
245 struct stat StatFd;
246 struct stat StatFile;
247 char TtyName[32];
248
249 //
250 // stat the file through the fd and tty name result.
251 //
252
253 for (Index = 0; Index < 3; ++Index)
254 {
255 LxtCheckErrno(ttyname_r(Index, TtyName, sizeof(TtyName)));
256 LxtLogInfo("Name %d: %s", Index, TtyName);
257 LxtCheckErrno(fstat(Index, &StatFd));
258 LxtCheckErrno(stat(TtyName, &StatFile));
259 LxtCheckEqual(StatFd.st_dev, StatFile.st_dev, "%d");
260 LxtCheckNotEqual(StatFd.st_dev, 0, "%d");
261 LxtCheckEqual(StatFd.st_ino, StatFile.st_ino, "%d");
262 LxtCheckNotEqual(StatFd.st_ino, 0, "%d");
263 LxtCheckEqual(StatFd.st_mode, StatFile.st_mode, "%d");
264 LxtCheckNotEqual(StatFd.st_mode, 0, "%d");
265 LxtCheckEqual(StatFd.st_nlink, StatFile.st_nlink, "%d");
266 LxtCheckEqual(StatFd.st_nlink, 1, "%d");
267 LxtCheckEqual(StatFd.st_uid, StatFile.st_uid, "%d");
268 LxtCheckEqual(StatFd.st_uid, 0, "%d");
269 LxtCheckEqual(StatFd.st_gid, StatFile.st_gid, "%d");
270 LxtCheckEqual(StatFd.st_gid, 5, "%d");
271 LxtCheckEqual(StatFd.st_rdev, StatFile.st_rdev, "%d");
272 LxtCheckNotEqual(StatFd.st_rdev, 0, "%d");
273 LxtCheckEqual(StatFd.st_size, StatFile.st_size, "%d");
274 LxtCheckEqual(StatFd.st_size, 0, "%d");
275 LxtCheckEqual(StatFd.st_blocks, StatFile.st_blocks, "%d");
276 LxtCheckEqual(StatFd.st_blocks, 0, "%d");
277 }
278
279 Result = 0;
280
281 ErrorExit:
282 return Result;
283 }
284
285 int TestDevTtyOpen(PLXT_ARGS Args)
286
287 {
288
289 ssize_t BytesRead;
290 int Index;
291 char LinkName[32];
292 char LinkTarget[32];
293 int Result;
294 struct stat StatFd;
295 struct stat StatFile;
296 int TtyFd;
297 char TtyName[32];
298 char TtyNameFd[32];
299
300 TtyFd = -1;
301
302 //
303 // Check that the current tty can be opened by name and is linked
304 // appropriately in procfs.
305 //
306
307 for (Index = 0; Index < 3; ++Index)
308 {
309 LxtCheckErrno(ttyname_r(Index, TtyName, sizeof(TtyName)));
310 LxtCheckErrno(TtyFd = open(TtyName, O_RDWR));
311 LxtCheckErrno(ttyname_r(TtyFd, TtyNameFd, sizeof(TtyNameFd)));
312 LxtCheckStringEqual(TtyName, TtyNameFd);
313
314 snprintf(LinkName, sizeof(LinkName), "/proc/self/fd/%d", Index);
315 LxtCheckErrno(BytesRead = readlink(LinkName, LinkTarget, sizeof(LinkTarget) - 1));
316 LinkTarget[BytesRead] = 0;
317 LxtCheckStringEqual(TtyName, LinkTarget);
318
319 snprintf(LinkName, sizeof(LinkName), "/proc/self/fd/%d", TtyFd);
320 LxtCheckErrno(BytesRead = readlink(LinkName, LinkTarget, sizeof(LinkTarget) - 1));
321 LinkTarget[BytesRead] = 0;
322 LxtCheckStringEqual(TtyName, LinkTarget);
323
324 LxtCheckErrno(fstat(TtyFd, &StatFd));
325 LxtCheckErrno(fstat(Index, &StatFile));
326 LxtCheckEqual(StatFd.st_ino, StatFile.st_ino, "%d");
327 LxtCheckEqual(StatFd.st_rdev, StatFile.st_rdev, "%d");
328 LxtClose(TtyFd);
329 TtyFd = -1;
330 }
331
332 //
333 // Check that /dev/tty0 fails to open, this behavior differs from native
334 // Linux.
335 //
336
337 LxtCheckErrnoFailure(TtyFd = open("/dev/tty0", O_RDWR), EIO);
338 Result = 0;
339
340 ErrorExit:
341 if (TtyFd != -1)
342 {
343 LxtClose(TtyFd);
344 }
345
346 return Result;
347 }
348
349 int TestDevTtySecurity(PLXT_ARGS Args)
350
351 {
352
353 bool ResetSecurity;
354 int Result;
355 struct stat Stat;
356 struct stat StatOriginal;
357 char TtyName[32];
358
359 ResetSecurity = false;
360 LxtCheckErrno(fstat(0, &StatOriginal));
361 ResetSecurity = true;
362 LxtCheckErrno(ttyname_r(0, TtyName, sizeof(TtyName)));
363
364 //
365 // Check that the uid, gid, and mode can be changed on the name or fd and
366 // are reflected into the stat on the fd and name
367 //
368
369 LxtCheckErrno(chmod(TtyName, LXT_NON_DEFAULT_MODE));
370 LxtCheckErrno(chown(TtyName, LXT_NON_DEFAULT_ID, LXT_NON_DEFAULT_ID));
371 LxtCheckErrno(fstat(0, &Stat));
372 LxtCheckEqual(Stat.st_mode, LXT_NON_DEFAULT_MODE, "%d");
373 LxtCheckEqual(Stat.st_uid, LXT_NON_DEFAULT_ID, "%d");
374 LxtCheckEqual(Stat.st_gid, LXT_NON_DEFAULT_ID, "%d");
375
376 LxtCheckErrno(fchmod(0, StatOriginal.st_mode));
377 LxtCheckErrno(fchown(0, StatOriginal.st_uid, StatOriginal.st_gid));
378 ResetSecurity = false;
379 LxtCheckErrno(stat(TtyName, &Stat));
380 LxtCheckEqual(Stat.st_mode, StatOriginal.st_mode, "%d");
381 LxtCheckEqual(Stat.st_uid, StatOriginal.st_uid, "%d");
382 LxtCheckEqual(Stat.st_gid, StatOriginal.st_gid, "%d");
383
384 Result = 0;
385
386 ErrorExit:
387 if (ResetSecurity != false)
388 {
389 fchmod(0, StatOriginal.st_mode);
390 fchown(0, StatOriginal.st_uid, StatOriginal.st_gid);
391 }
392
393 return Result;
394 }