master
c 296 lines 6.49 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 dup.c
8
9 Abstract:
10
11 This file is a test for the dup, dup2 system call.
12
13 --*/
14
15 #include "lxtcommon.h"
16 #include "unittests.h"
17 #include <errno.h>
18 #include <sys/types.h>
19 #include <sys/wait.h>
20
21 #if !defined(__amd64__) && !defined(__aarch64__)
22 #include <sys/limits.h>
23 #endif
24
25 #include <fcntl.h>
26
27 #define LXT_NAME "Dup"
28 #define FD_INVALID (-1)
29 #define FD_STDIN 0
30 #define FD_STDOUT 1
31 #define FD_ERR 2
32 #define MY_F_DUPFD_CLOEXEC 1030
33
34 int Dup0(PLXT_ARGS Args);
35
36 int Dup1(PLXT_ARGS Args);
37
38 int Dup2(PLXT_ARGS Args);
39
40 //
41 // Global constants
42 //
43
44 static const LXT_VARIATION g_LxtVariations[] = {{"Dup Basic", Dup0}, {"Dup Descriptor Flags", Dup1}, {"FCNTL Dup Error Cases", Dup2}};
45
46 int DupTestEntry(int Argc, char* Argv[])
47
48 /*++
49
50 Routine Description:
51
52 This routine main entry point for the test for dup, dup2 system call.
53
54 Arguments:
55
56 Argc - Supplies the number of command line arguments.
57
58 Argv - Supplies the command line arguments.
59
60 Return Value:
61
62 Returns 0 on success, -1 on failure.
63
64 --*/
65
66 {
67
68 LXT_ARGS Args;
69 int Result;
70
71 LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
72 LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
73
74 ErrorExit:
75 LxtUninitialize();
76 return !LXT_SUCCESS(Result);
77 }
78
79 int Dup0(PLXT_ARGS Args)
80
81 /*++
82
83 Routine Description:
84
85 This routine validates that the dup and dup2 system call and the
86 various parameter variances.
87
88 Arguments:
89
90 Args - Supplies the command line arguments.
91
92 Return Value:
93
94 Returns 0 on success, -1 on failure.
95
96 --*/
97
98 {
99
100 int Result;
101 int DupStdIn;
102 int DupStdOut;
103 int DupFd2;
104
105 LxtCheckErrnoFailure(dup(FD_INVALID), EBADF);
106 LxtCheckErrnoFailure(dup(__SHRT_MAX__), EBADF);
107 LxtCheckResult((DupStdIn = dup(FD_STDIN)));
108 LxtCheckResult(close(FD_STDIN));
109 LxtCheckResult((DupStdOut = dup(FD_STDOUT)));
110
111 //
112 // Since we just closed STDIN, duping STDOUT should take the position
113 // of STDIN
114 //
115
116 if (DupStdOut != FD_STDIN)
117 {
118 LxtLogError("Dup, expected FD return value(%d), actual(%d).", FD_STDIN, DupStdOut);
119 Result = LXT_RESULT_FAILURE;
120 goto ErrorExit;
121 }
122
123 //
124 // Now forcefully restore STDIN to its rightful position using dup2
125 //
126
127 LxtCheckResult((DupFd2 = dup2(DupStdIn, FD_STDIN)));
128 if (DupFd2 != FD_STDIN)
129 {
130 LxtLogError("Dup, expected FD return value(%d), actual(%d).", FD_STDIN, DupFd2);
131 Result = LXT_RESULT_FAILURE;
132 goto ErrorExit;
133 }
134
135 Result = LXT_RESULT_SUCCESS;
136
137 ErrorExit:
138 return Result;
139 }
140
141 int Dup1(PLXT_ARGS Args)
142
143 /*++
144
145 Routine Description:
146
147 This routine validates that the variations of the dup system calls,
148 and their behavior w.r.t sharing file descriptor flags.
149
150 Arguments:
151
152 Args - Supplies the command line arguments.
153
154 Return Value:
155
156 Returns 0 on success, -1 on failure.
157
158 --*/
159
160 {
161
162 int Result;
163 int FdProcSelf;
164 int FdProcSelfFlags;
165 int FdDup;
166 int FdDupFlags;
167 int FdTemp;
168
169 LxtCheckResult((FdProcSelf = open("/proc/self", O_RDONLY | O_CLOEXEC)));
170 LxtCheckResult((FdDup = dup(FdProcSelf)));
171 LxtCheckResult((FdProcSelfFlags = fcntl(FdProcSelf, F_GETFD)));
172 LxtCheckResult((FdDupFlags = fcntl(FdDup, F_GETFD)));
173
174 if ((FdProcSelfFlags & FD_CLOEXEC) == 0)
175 {
176 LxtLogError("/proc/self FD should have the 'FD_CLOEXEC' flag set, ", "but it is not. FD Flags(%d).", FdProcSelfFlags);
177 Result = LXT_RESULT_FAILURE;
178 goto ErrorExit;
179 }
180
181 //
182 // Dup should not share file descriptor flags
183 //
184
185 if ((FdDupFlags & FD_CLOEXEC) != 0)
186 {
187 LxtLogError(
188 "Dup should not share File Descriptor Flags between "
189 "the old and new descriptor. New Descriptor Flags(%d).",
190 FdDupFlags);
191 Result = LXT_RESULT_FAILURE;
192 goto ErrorExit;
193 }
194
195 LxtCheckResult(close(FdDup));
196 LxtCheckResult((FdTemp = fcntl(FdProcSelf, F_DUPFD, FdDup)));
197 if (FdTemp != FdDup)
198 {
199 LxtLogError(
200 "fcntl(F_DUPFD) should return(%d), but "
201 "it returned fd(%d).",
202 FdDup,
203 FdTemp);
204 Result = LXT_RESULT_FAILURE;
205 goto ErrorExit;
206 }
207
208 LxtCheckResult((FdDupFlags = fcntl(FdDup, F_GETFD)));
209
210 //
211 // fcntl(F_DUPFD) should not set the FD_CLOEXEC in the new descriptor
212 //
213
214 if ((FdDupFlags & FD_CLOEXEC) != 0)
215 {
216 LxtLogError(
217 "fcntl(F_DUPFD) should not share File Descriptor Flags "
218 "between the old and new descriptor. New Descriptor "
219 "Flags(%d).",
220 FdDupFlags);
221 Result = LXT_RESULT_FAILURE;
222 goto ErrorExit;
223 }
224
225 LxtCheckResult(close(FdDup));
226 LxtCheckResult((FdTemp = fcntl(FdProcSelf, MY_F_DUPFD_CLOEXEC, FdDup)));
227 if (FdTemp != FdDup)
228 {
229 LxtLogError(
230 "fcntl(F_DUPFD_CLOEXEC) should return(%d), but "
231 "it returned fd(%d).",
232 FdDup,
233 FdTemp);
234 Result = LXT_RESULT_FAILURE;
235 goto ErrorExit;
236 }
237
238 LxtCheckResult((FdDupFlags = fcntl(FdDup, F_GETFD)));
239
240 //
241 // fcntl(F_DUPFD_CLOEXEC) should set the FD_CLOEXEC in the new descriptor
242 //
243
244 if ((FdDupFlags & FD_CLOEXEC) == 0)
245 {
246 LxtLogError(
247 "fcntl(F_DUPFD_CLOEXEC) should set the FD_CLOEXEC flag "
248 "in the new descriptor. New Descriptor "
249 "Flags(%d).",
250 FdDupFlags);
251 Result = LXT_RESULT_FAILURE;
252 goto ErrorExit;
253 }
254
255 Result = LXT_RESULT_SUCCESS;
256
257 ErrorExit:
258 return Result;
259 }
260
261 int Dup2(PLXT_ARGS Args)
262
263 /*++
264
265 Routine Description:
266
267 This routine validates the error cases for FCNTL calls related to dup.
268
269 Arguments:
270
271 Args - Supplies the command line arguments.
272
273 Return Value:
274
275 Returns 0 on success, -1 on failure.
276
277 --*/
278
279 {
280
281 int Result;
282
283 LxtCheckErrnoFailure(fcntl(FD_INVALID, F_DUPFD, 0), EBADF);
284 LxtCheckErrnoFailure(fcntl(FD_INVALID, MY_F_DUPFD_CLOEXEC, 0), EBADF);
285 LxtCheckErrnoFailure(fcntl(FD_STDIN, F_DUPFD, FD_INVALID), EINVAL);
286 LxtCheckErrnoFailure(fcntl(FD_STDIN, MY_F_DUPFD_CLOEXEC, FD_INVALID), EINVAL);
287
288 //
289 // TODO: Add cases where the FD to dup into in FCNTL is > max allowed
290 //
291
292 Result = LXT_RESULT_SUCCESS;
293
294 ErrorExit:
295 return Result;
296 }