]> git.ozlabs.org Git - ccan/blob - ccan/closefrom/test/run.c
closefrom: Close all file descriptors above a certain value.
[ccan] / ccan / closefrom / test / run.c
1 #include <ccan/closefrom/closefrom.h>
2 /* Include the C files directly. */
3 #include <ccan/closefrom/closefrom.c>
4 #include <ccan/tap/tap.h>
5 #include <errno.h>
6 #include <sys/types.h>
7 #include <sys/wait.h>
8 #include <unistd.h>
9
10 /* Open a pipe, do closefrom, check pipe no longer works.   */
11 static
12 int pipe_close(void)
13 {
14         int fds[2];
15         ssize_t wres;
16
17         char buf = '\0';
18
19         if (pipe(fds) < 0)
20                 return 0;
21
22         /* Writing to the write end should succeed, the
23          * pipe is working.  */
24         do {
25                 wres = write(fds[1], &buf, 1);
26         } while ((wres < 0) && (errno == EINTR));
27         if (wres < 0)
28                 return 0;
29
30         closefrom(STDERR_FILENO + 1);
31
32         /* Writing to the write end should fail because
33          * everything should be closed.  */
34         do {
35                 wres = write(fds[1], &buf, 1);
36         } while ((wres < 0) && (errno == EINTR));
37
38         return (wres < 0) && (errno == EBADF);
39 }
40
41 /* Open a pipe, fork, do closefrom in child, read pipe from parent,
42  * parent should see EOF.
43  */
44 static
45 int fork_close(void)
46 {
47         int fds[2];
48         pid_t child;
49
50         char buf;
51         ssize_t rres;
52
53         if (pipe(fds) < 0)
54                 return 0;
55
56         child = fork();
57         if (child < 0)
58                 return 0;
59
60         if (child == 0) {
61                 /* Child.  */
62                 closefrom(STDERR_FILENO + 1);
63                 _exit(0);
64         } else {
65                 /* Parent.  */
66
67                 /* Close write end of pipe.  */
68                 close(fds[1]);
69
70                 do {
71                         rres = read(fds[0], &buf, 1);
72                 } while ((rres < 0) && (errno == EINTR));
73
74                 /* Should have seen EOF.  */
75                 if (rres != 0)
76                         return 0;
77
78                 /* Clean up.  */
79                 waitpid(child, NULL, 0);
80                 closefrom(STDERR_FILENO + 1);
81         }
82
83         return 1;
84 }
85 /* Open a pipe, fork, in child set the write end to fd #3,
86  * in parent set the read end to fd #3, send a byte from
87  * child to parent, check.
88  */
89 static
90 int fork_communicate()
91 {
92         int fds[2];
93         pid_t child;
94
95         char wbuf = 42;
96         char rbuf;
97         ssize_t rres;
98         ssize_t wres;
99
100         int status;
101
102         if (pipe(fds) < 0)
103                 return 0;
104
105         child = fork();
106         if (child < 0)
107                 return 0;
108
109         if (child == 0) {
110                 /* Child.  */
111
112                 /* Move write end to fd #3.  */
113                 if (fds[1] != 3) {
114                         if (dup2(fds[1], 3) < 0)
115                                 _exit(127);
116                         close(fds[1]);
117                         fds[1] = 3;
118                 }
119
120                 closefrom(4);
121
122                 do {
123                         wres = write(fds[1], &wbuf, 1);
124                 } while ((wres < 0) && (errno == EINTR));
125                 if (wres < 0)
126                         _exit(127);
127
128                 _exit(0);
129         } else {
130                 /* Parent.  */
131
132                 /* Move read end to fd #3.  */
133                 if (fds[0] != 3) {
134                         if (dup2(fds[0], 3) < 0)
135                                 return 0;
136                         close(fds[0]);
137                         fds[0] = 3;
138                 }
139
140                 closefrom(4);
141
142                 /* Wait for child to finish.  */
143                 waitpid(child, &status, 0);
144                 if (!WIFEXITED(status))
145                         return 0;
146                 if (WEXITSTATUS(status) != 0)
147                         return 0;
148
149                 /* Read 1 byte.  */
150                 do {
151                         rres = read(fds[0], &rbuf, 1);
152                 } while ((rres < 0) && (errno == EINTR));
153                 if (rres < 0)
154                         return 0;
155                 if (rres != 1)
156                         return 0;
157                 /* Should get same byte as what was sent.  */
158                 if (rbuf != wbuf)
159                         return 0;
160
161                 /* Next attempt to read should EOF.  */
162                 do {
163                         rres = read(fds[0], &rbuf, 1);
164                 } while ((rres < 0) && (errno == EINTR));
165                 if (rres < 0)
166                         return 0;
167                 /* Should EOF.  */
168                 if (rres != 0)
169                         return 0;
170
171         }
172
173         /* Clean up.  */
174         close(fds[0]);
175         return 1;
176 }
177
178 int main(void)
179 {
180         /* Limit closefrom.  */
181         closefrom_limit(0);
182
183         /* This is how many tests you plan to run */
184         plan_tests(3);
185
186         ok1(pipe_close());
187         ok1(fork_close());
188         ok1(fork_communicate());
189
190         /* This exits depending on whether all tests passed */
191         return exit_status();
192 }