1 /* $OpenBSD: dup2_self.c,v 1.3 2003/07/31 21:48:08 deraadt Exp $ */
2 /*
3 * Written by Artur Grabowski <art@openbsd.org> 2002 Public Domain.
4 */
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <err.h>
9 #include <fcntl.h>
10
11 /*
12 * We're testing a small tweak in dup2 semantics. Normally dup and dup2
13 * will clear the close-on-exec flag on the new fd (which appears to be
14 * an implementation mistake from start and not some planned behavior).
15 * In todays implementations of dup and dup2 we have to make an effort
16 * to really clear that flag. But all tested implementations of dup2 have
17 * another tweak. If we dup2(old, new) when old == new, the syscall
18 * short-circuits and returns early (because there is no need to do all
19 * the work (and there is a risk for serious mistakes)). So although the
20 * docs say that dup2 should "take 'old', close 'new' perform a dup(2) of
21 * 'old' into 'new'" the docs are not really followed because close-on-exec
22 * is not cleared on 'new'.
23 *
24 * Since everyone has this bug, we pretend that this is the way it is
25 * supposed to be and test here that it really works that way.
26 *
27 * This is a fine example on where two separate implementation fuckups
28 * take out each other and make the end-result the way it was meant to be.
29 */
30
31 int
main(int argc,char * argv[])32 main(int argc, char *argv[])
33 {
34 int orgfd, fd1, fd2;
35 char temp[] = "/tmp/dup2XXXXXXXXX";
36
37 if ((orgfd = mkstemp(temp)) < 0)
38 err(1, "mkstemp");
39 remove(temp);
40
41 if (ftruncate(orgfd, 1024) != 0)
42 err(1, "ftruncate");
43
44 if ((fd1 = dup(orgfd)) < 0)
45 err(1, "dup");
46
47 /* Set close-on-exec */
48 if (fcntl(fd1, F_SETFD, 1) != 0)
49 err(1, "fcntl(F_SETFD)");
50
51 if ((fd2 = dup2(fd1, fd1)) < 0)
52 err(1, "dup2");
53
54 /* Test 1: Do we get the right fd? */
55 if (fd2 != fd1)
56 errx(1, "dup2 didn't give us the right fd");
57
58 /* Test 2: Was close-on-exec cleared? */
59 if (fcntl(fd2, F_GETFD) == 0)
60 errx(1, "dup2 cleared close-on-exec");
61
62 return 0;
63 }
64