1219820Sjeff/* 2219820Sjeff * $OpenBSD: dup2test.c,v 1.3 2003/07/31 21:48:08 deraadt Exp $ 3219820Sjeff * $OpenBSD: dup2_self.c,v 1.3 2003/07/31 21:48:08 deraadt Exp $ 4219820Sjeff * $OpenBSD: fcntl_dup.c,v 1.2 2003/07/31 21:48:08 deraadt Exp $ 5219820Sjeff * 6219820Sjeff * Written by Artur Grabowski <art@openbsd.org> 2002 Public Domain. 7219820Sjeff * 8219820Sjeff * $FreeBSD$ 9219820Sjeff */ 10219820Sjeff 11219820Sjeff/* 12219820Sjeff * Test #1: check if dup(2) works. 13219820Sjeff * Test #2: check if dup2(2) works. 14219820Sjeff * Test #3: check if dup2(2) returned a fd we asked for. 15219820Sjeff * Test #4: check if dup2(2) cleared close-on-exec flag for duped fd. 16219820Sjeff * Test #5: check if dup2(2) allows to dup fd to itself. 17219820Sjeff * Test #6: check if dup2(2) returned a fd we asked for. 18219820Sjeff * Test #7: check if dup2(2) did not clear close-on-exec flag for duped fd. 19219820Sjeff * Test #8: check if fcntl(F_DUPFD) works. 20219820Sjeff * Test #9: check if fcntl(F_DUPFD) cleared close-on-exec flag for duped fd. 21219820Sjeff * Test #10: check if dup2() to a fd > current maximum number of open files 22219820Sjeff * limit work. 23219820Sjeff * Test #11: check if fcntl(F_DUP2FD) works. 24219820Sjeff * Test #12: check if fcntl(F_DUP2FD) returned a fd we asked for. 25219820Sjeff * Test #13: check if fcntl(F_DUP2FD) cleared close-on-exec flag for duped fd. 26219820Sjeff * Test #14: check if fcntl(F_DUP2FD) allows to dup fd to itself. 27219820Sjeff * Test #15: check if fcntl(F_DUP2FD) returned a fd we asked for. 28219820Sjeff * Test #16: check if fcntl(F_DUP2FD) did not clear close-on-exec flag for 29219820Sjeff * duped fd. 30219820Sjeff * Test #17: check if fcntl(F_DUP2FD) to a fd > current maximum number of open 31219820Sjeff * files limit work. 32219820Sjeff * Test #18: check if fcntl(F_DUPFD_CLOEXEC) works. 33219820Sjeff * Test #19: check if fcntl(F_DUPFD_CLOEXEC) set close-on-exec flag for duped 34219820Sjeff * fd. 35219820Sjeff * Test #20: check if fcntl(F_DUP2FD_CLOEXEC) works. 36219820Sjeff * Test #21: check if fcntl(F_DUP2FD_CLOEXEC) returned a fd we asked for. 37219820Sjeff * Test #22: check if fcntl(F_DUP2FD_CLOEXEC) set close-on-exec flag for duped 38219820Sjeff * fd. 39219820Sjeff * Test #23: check if fcntl(F_DUP2FD_CLOEXEC) to a fd > current maximum number 40219820Sjeff * of open files limit work. 41219820Sjeff * Test #24: check if dup3(O_CLOEXEC) works. 42219820Sjeff * Test #25: check if dup3(O_CLOEXEC) returned a fd we asked for. 43219820Sjeff * Test #26: check if dup3(O_CLOEXEC) set close-on-exec flag for duped fd. 44219820Sjeff * Test #27: check if dup3(0) works. 45219820Sjeff * Test #28: check if dup3(0) returned a fd we asked for. 46219820Sjeff * Test #29: check if dup3(0) cleared close-on-exec flag for duped fd. 47219820Sjeff * Test #30: check if dup3(O_CLOEXEC) fails if oldfd == newfd. 48219820Sjeff * Test #31: check if dup3(0) fails if oldfd == newfd. 49219820Sjeff * Test #32: check if dup3(O_CLOEXEC) to a fd > current maximum number of 50219820Sjeff * open files limit work. 51219820Sjeff */ 52219820Sjeff 53219820Sjeff#include <sys/types.h> 54219820Sjeff#include <sys/time.h> 55219820Sjeff#include <sys/resource.h> 56219820Sjeff 57219820Sjeff#include <err.h> 58219820Sjeff#include <fcntl.h> 59#include <stdio.h> 60#include <stdlib.h> 61#include <unistd.h> 62 63static int getafile(void); 64 65static int 66getafile(void) 67{ 68 int fd; 69 70 char temp[] = "/tmp/dup2XXXXXXXXX"; 71 if ((fd = mkstemp(temp)) < 0) 72 err(1, "mkstemp"); 73 remove(temp); 74 if (ftruncate(fd, 1024) != 0) 75 err(1, "ftruncate"); 76 return (fd); 77} 78 79int 80main(int __unused argc, char __unused *argv[]) 81{ 82 struct rlimit rlp; 83 int orgfd, fd1, fd2, test = 0; 84 85 orgfd = getafile(); 86 87 printf("1..32\n"); 88 89 /* If dup(2) ever work? */ 90 if ((fd1 = dup(orgfd)) < 0) 91 err(1, "dup"); 92 printf("ok %d - dup(2) works\n", ++test); 93 94 /* Set close-on-exec */ 95 if (fcntl(fd1, F_SETFD, 1) != 0) 96 err(1, "fcntl(F_SETFD)"); 97 98 /* If dup2(2) ever work? */ 99 if ((fd2 = dup2(fd1, fd1 + 1)) < 0) 100 err(1, "dup2"); 101 printf("ok %d - dup2(2) works\n", ++test); 102 103 /* Do we get the right fd? */ 104 ++test; 105 if (fd2 != fd1 + 1) 106 printf("no ok %d - dup2(2) didn't give us the right fd\n", 107 test); 108 else 109 printf("ok %d - dup2(2) returned a correct fd\n", test); 110 111 /* Was close-on-exec cleared? */ 112 ++test; 113 if (fcntl(fd2, F_GETFD) != 0) 114 printf("not ok %d - dup2(2) didn't clear close-on-exec\n", 115 test); 116 else 117 printf("ok %d - dup2(2) cleared close-on-exec\n", test); 118 119 /* 120 * Dup to itself. 121 * 122 * We're testing a small tweak in dup2 semantics. 123 * Normally dup and dup2 will clear the close-on-exec 124 * flag on the new fd (which appears to be an implementation 125 * mistake from start and not some planned behavior). 126 * In today's implementations of dup and dup2 we have to make 127 * an effort to really clear that flag. But all tested 128 * implementations of dup2 have another tweak. If we 129 * dup2(old, new) when old == new, the syscall short-circuits 130 * and returns early (because there is no need to do all the 131 * work (and there is a risk for serious mistakes)). 132 * So although the docs say that dup2 should "take 'old', 133 * close 'new' perform a dup(2) of 'old' into 'new'" 134 * the docs are not really followed because close-on-exec 135 * is not cleared on 'new'. 136 * 137 * Since everyone has this bug, we pretend that this is 138 * the way it is supposed to be and test here that it really 139 * works that way. 140 * 141 * This is a fine example on where two separate implementation 142 * fuckups take out each other and make the end-result the way 143 * it was meant to be. 144 */ 145 if ((fd2 = dup2(fd1, fd1)) < 0) 146 err(1, "dup2"); 147 printf("ok %d - dup2(2) to itself works\n", ++test); 148 149 /* Do we get the right fd? */ 150 ++test; 151 if (fd2 != fd1) 152 printf("not ok %d - dup2(2) didn't give us the right fd\n", 153 test); 154 else 155 printf("ok %d - dup2(2) to itself returned a correct fd\n", 156 test); 157 158 /* Was close-on-exec cleared? */ 159 ++test; 160 if (fcntl(fd2, F_GETFD) == 0) 161 printf("not ok %d - dup2(2) cleared close-on-exec\n", test); 162 else 163 printf("ok %d - dup2(2) didn't clear close-on-exec\n", test); 164 165 /* Does fcntl(F_DUPFD) work? */ 166 if ((fd2 = fcntl(fd1, F_DUPFD, 10)) < 0) 167 err(1, "fcntl(F_DUPFD)"); 168 if (fd2 < 10) 169 printf("not ok %d - fcntl(F_DUPFD) returned wrong fd %d\n", 170 ++test, fd2); 171 else 172 printf("ok %d - fcntl(F_DUPFD) works\n", ++test); 173 174 /* Was close-on-exec cleared? */ 175 ++test; 176 if (fcntl(fd2, F_GETFD) != 0) 177 printf( 178 "not ok %d - fcntl(F_DUPFD) didn't clear close-on-exec\n", 179 test); 180 else 181 printf("ok %d - fcntl(F_DUPFD) cleared close-on-exec\n", test); 182 183 ++test; 184 if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) 185 err(1, "getrlimit"); 186 if ((fd2 = dup2(fd1, rlp.rlim_cur + 1)) >= 0) 187 printf("not ok %d - dup2(2) bypassed NOFILE limit\n", test); 188 else 189 printf("ok %d - dup2(2) didn't bypass NOFILE limit\n", test); 190 191 /* If fcntl(F_DUP2FD) ever work? */ 192 if ((fd2 = fcntl(fd1, F_DUP2FD, fd1 + 1)) < 0) 193 err(1, "fcntl(F_DUP2FD)"); 194 printf("ok %d - fcntl(F_DUP2FD) works\n", ++test); 195 196 /* Do we get the right fd? */ 197 ++test; 198 if (fd2 != fd1 + 1) 199 printf( 200 "no ok %d - fcntl(F_DUP2FD) didn't give us the right fd\n", 201 test); 202 else 203 printf("ok %d - fcntl(F_DUP2FD) returned a correct fd\n", 204 test); 205 206 /* Was close-on-exec cleared? */ 207 ++test; 208 if (fcntl(fd2, F_GETFD) != 0) 209 printf( 210 "not ok %d - fcntl(F_DUP2FD) didn't clear close-on-exec\n", 211 test); 212 else 213 printf("ok %d - fcntl(F_DUP2FD) cleared close-on-exec\n", 214 test); 215 216 /* Dup to itself */ 217 if ((fd2 = fcntl(fd1, F_DUP2FD, fd1)) < 0) 218 err(1, "fcntl(F_DUP2FD)"); 219 printf("ok %d - fcntl(F_DUP2FD) to itself works\n", ++test); 220 221 /* Do we get the right fd? */ 222 ++test; 223 if (fd2 != fd1) 224 printf( 225 "not ok %d - fcntl(F_DUP2FD) didn't give us the right fd\n", 226 test); 227 else 228 printf( 229 "ok %d - fcntl(F_DUP2FD) to itself returned a correct fd\n", 230 test); 231 232 /* Was close-on-exec cleared? */ 233 ++test; 234 if (fcntl(fd2, F_GETFD) == 0) 235 printf("not ok %d - fcntl(F_DUP2FD) cleared close-on-exec\n", 236 test); 237 else 238 printf("ok %d - fcntl(F_DUP2FD) didn't clear close-on-exec\n", 239 test); 240 241 ++test; 242 if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) 243 err(1, "getrlimit"); 244 if ((fd2 = fcntl(fd1, F_DUP2FD, rlp.rlim_cur + 1)) >= 0) 245 printf("not ok %d - fcntl(F_DUP2FD) bypassed NOFILE limit\n", 246 test); 247 else 248 printf("ok %d - fcntl(F_DUP2FD) didn't bypass NOFILE limit\n", 249 test); 250 251 /* Does fcntl(F_DUPFD_CLOEXEC) work? */ 252 if ((fd2 = fcntl(fd1, F_DUPFD_CLOEXEC, 10)) < 0) 253 err(1, "fcntl(F_DUPFD_CLOEXEC)"); 254 if (fd2 < 10) 255 printf("not ok %d - fcntl(F_DUPFD_CLOEXEC) returned wrong fd %d\n", 256 ++test, fd2); 257 else 258 printf("ok %d - fcntl(F_DUPFD_CLOEXEC) works\n", ++test); 259 260 /* Was close-on-exec cleared? */ 261 ++test; 262 if (fcntl(fd2, F_GETFD) != 1) 263 printf( 264 "not ok %d - fcntl(F_DUPFD_CLOEXEC) didn't set close-on-exec\n", 265 test); 266 else 267 printf("ok %d - fcntl(F_DUPFD_CLOEXEC) set close-on-exec\n", 268 test); 269 270 /* If fcntl(F_DUP2FD_CLOEXEC) ever work? */ 271 if ((fd2 = fcntl(fd1, F_DUP2FD_CLOEXEC, fd1 + 1)) < 0) 272 err(1, "fcntl(F_DUP2FD_CLOEXEC)"); 273 printf("ok %d - fcntl(F_DUP2FD_CLOEXEC) works\n", ++test); 274 275 /* Do we get the right fd? */ 276 ++test; 277 if (fd2 != fd1 + 1) 278 printf( 279 "no ok %d - fcntl(F_DUP2FD_CLOEXEC) didn't give us the right fd\n", 280 test); 281 else 282 printf("ok %d - fcntl(F_DUP2FD_CLOEXEC) returned a correct fd\n", 283 test); 284 285 /* Was close-on-exec set? */ 286 ++test; 287 if (fcntl(fd2, F_GETFD) != FD_CLOEXEC) 288 printf( 289 "not ok %d - fcntl(F_DUP2FD_CLOEXEC) didn't set close-on-exec\n", 290 test); 291 else 292 printf("ok %d - fcntl(F_DUP2FD_CLOEXEC) set close-on-exec\n", 293 test); 294 295 /* 296 * It is unclear what F_DUP2FD_CLOEXEC should do when duplicating a 297 * file descriptor onto itself. 298 */ 299 300 ++test; 301 if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) 302 err(1, "getrlimit"); 303 if ((fd2 = fcntl(fd1, F_DUP2FD_CLOEXEC, rlp.rlim_cur + 1)) >= 0) 304 printf("not ok %d - fcntl(F_DUP2FD_CLOEXEC) bypassed NOFILE limit\n", 305 test); 306 else 307 printf("ok %d - fcntl(F_DUP2FD_CLOEXEC) didn't bypass NOFILE limit\n", 308 test); 309 310 /* Does dup3(O_CLOEXEC) ever work? */ 311 if ((fd2 = dup3(fd1, fd1 + 1, O_CLOEXEC)) < 0) 312 err(1, "dup3(O_CLOEXEC)"); 313 printf("ok %d - dup3(O_CLOEXEC) works\n", ++test); 314 315 /* Do we get the right fd? */ 316 ++test; 317 if (fd2 != fd1 + 1) 318 printf( 319 "no ok %d - dup3(O_CLOEXEC) didn't give us the right fd\n", 320 test); 321 else 322 printf("ok %d - dup3(O_CLOEXEC) returned a correct fd\n", 323 test); 324 325 /* Was close-on-exec set? */ 326 ++test; 327 if (fcntl(fd2, F_GETFD) != FD_CLOEXEC) 328 printf( 329 "not ok %d - dup3(O_CLOEXEC) didn't set close-on-exec\n", 330 test); 331 else 332 printf("ok %d - dup3(O_CLOEXEC) set close-on-exec\n", 333 test); 334 335 /* Does dup3(0) ever work? */ 336 if ((fd2 = dup3(fd1, fd1 + 1, 0)) < 0) 337 err(1, "dup3(0)"); 338 printf("ok %d - dup3(0) works\n", ++test); 339 340 /* Do we get the right fd? */ 341 ++test; 342 if (fd2 != fd1 + 1) 343 printf( 344 "no ok %d - dup3(0) didn't give us the right fd\n", 345 test); 346 else 347 printf("ok %d - dup3(0) returned a correct fd\n", 348 test); 349 350 /* Was close-on-exec cleared? */ 351 ++test; 352 if (fcntl(fd2, F_GETFD) != 0) 353 printf( 354 "not ok %d - dup3(0) didn't clear close-on-exec\n", 355 test); 356 else 357 printf("ok %d - dup3(0) cleared close-on-exec\n", 358 test); 359 360 /* dup3() does not allow duplicating to the same fd */ 361 ++test; 362 if (dup3(fd1, fd1, O_CLOEXEC) != -1) 363 printf( 364 "not ok %d - dup3(fd1, fd1, O_CLOEXEC) succeeded\n", test); 365 else 366 printf("ok %d - dup3(fd1, fd1, O_CLOEXEC) failed\n", test); 367 368 ++test; 369 if (dup3(fd1, fd1, 0) != -1) 370 printf( 371 "not ok %d - dup3(fd1, fd1, 0) succeeded\n", test); 372 else 373 printf("ok %d - dup3(fd1, fd1, 0) failed\n", test); 374 375 ++test; 376 if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) 377 err(1, "getrlimit"); 378 if ((fd2 = dup3(fd1, rlp.rlim_cur + 1, O_CLOEXEC)) >= 0) 379 printf("not ok %d - dup3(O_CLOEXEC) bypassed NOFILE limit\n", 380 test); 381 else 382 printf("ok %d - dup3(O_CLOEXEC) didn't bypass NOFILE limit\n", 383 test); 384 385 return (0); 386} 387