1 /*-
2 * Copyright (c) 2007 Robert N. M. Watson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 /*
28 * A few regression tests for UNIX domain sockets. Run from single-user mode
29 * as it checks the openfiles sysctl to look for leaks, and we don't want that
30 * changing due to other processes doing stuff.
31 */
32
33 #include <sys/types.h>
34 #include <sys/signal.h>
35 #include <sys/socket.h>
36 #include <sys/sysctl.h>
37 #include <sys/un.h>
38 #include <sys/wait.h>
39
40 #include <netinet/in.h>
41
42 #include <err.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <limits.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50
51 static int forcegc = 1;
52 static char dpath[PATH_MAX];
53 static const char *test;
54
55 static int
getsysctl(const char * name)56 getsysctl(const char *name)
57 {
58 size_t len;
59 int i;
60
61 len = sizeof(i);
62 if (sysctlbyname(name, &i, &len, NULL, 0) < 0)
63 err(-1, "%s", name);
64 return (i);
65 }
66
67 static int
getopenfiles(void)68 getopenfiles(void)
69 {
70
71 return (getsysctl("kern.openfiles"));
72 }
73
74 static int
getinflight(void)75 getinflight(void)
76 {
77
78 return (getsysctl("net.local.inflight"));
79 }
80
81 static int
getdeferred(void)82 getdeferred(void)
83 {
84
85 return (getsysctl("net.local.deferred"));
86 }
87
88 static void
sendfd(int fd,int fdtosend)89 sendfd(int fd, int fdtosend)
90 {
91 struct msghdr mh;
92 struct message { struct cmsghdr msg_hdr; int fd; } m;
93 ssize_t len;
94 int after_inflight, before_inflight;
95
96 before_inflight = getinflight();
97
98 bzero(&mh, sizeof(mh));
99 bzero(&m, sizeof(m));
100 mh.msg_control = &m;
101 mh.msg_controllen = sizeof(m);
102 m.msg_hdr.cmsg_len = sizeof(m);
103 m.msg_hdr.cmsg_level = SOL_SOCKET;
104 m.msg_hdr.cmsg_type = SCM_RIGHTS;
105 m.fd = fdtosend;
106 len = sendmsg(fd, &mh, 0);
107 if (len < 0)
108 err(-1, "%s: sendmsg", test);
109 after_inflight = getinflight();
110 if (after_inflight != before_inflight + 1)
111 errx(-1, "%s: sendfd: before %d after %d\n", test,
112 before_inflight, after_inflight);
113 }
114
115 static void
close2(int fd1,int fd2)116 close2(int fd1, int fd2)
117 {
118
119 close(fd1);
120 close(fd2);
121 }
122
123 static void
close3(int fd1,int fd2,int fd3)124 close3(int fd1, int fd2, int fd3)
125 {
126
127 close2(fd1, fd2);
128 close(fd3);
129 }
130
131 static void
close4(int fd1,int fd2,int fd3,int fd4)132 close4(int fd1, int fd2, int fd3, int fd4)
133 {
134
135 close2(fd1, fd2);
136 close2(fd3, fd4);
137 }
138
139 static void
close5(int fd1,int fd2,int fd3,int fd4,int fd5)140 close5(int fd1, int fd2, int fd3, int fd4, int fd5)
141 {
142
143 close3(fd1, fd2, fd3);
144 close2(fd4, fd5);
145 }
146
147 static int
my_socket(int domain,int type,int proto)148 my_socket(int domain, int type, int proto)
149 {
150 int sock;
151
152 sock = socket(domain, type, proto);
153 if (sock < 0)
154 err(-1, "%s: socket", test);
155 return (sock);
156 }
157
158 static void
my_bind(int sock,struct sockaddr * sa,socklen_t len)159 my_bind(int sock, struct sockaddr *sa, socklen_t len)
160 {
161
162 if (bind(sock, sa, len) < 0)
163 err(-1, "%s: bind", test);
164 }
165
166 static void
my_connect(int sock,struct sockaddr * sa,socklen_t len)167 my_connect(int sock, struct sockaddr *sa, socklen_t len)
168 {
169
170 if (connect(sock, sa, len) < 0 && errno != EINPROGRESS)
171 err(-1, "%s: connect", test);
172 }
173
174 static void
my_listen(int sock,int backlog)175 my_listen(int sock, int backlog)
176 {
177
178 if (listen(sock, backlog) < 0)
179 err(-1, "%s: listen", test);
180 }
181
182 static void
my_socketpair(int * sv)183 my_socketpair(int *sv)
184 {
185
186 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0)
187 err(-1, "%s: socketpair", test);
188 }
189
190 static void
my_getsockname(int s,struct sockaddr * sa,socklen_t * salen)191 my_getsockname(int s, struct sockaddr *sa, socklen_t *salen)
192 {
193
194 if (getsockname(s, sa, salen) < 0)
195 err(-1, "%s: getsockname", test);
196 }
197
198 static void
setnonblock(int s)199 setnonblock(int s)
200 {
201
202 if (fcntl(s, F_SETFL, O_NONBLOCK) < 0)
203 err(-1, "%s: fcntl(F_SETFL, O_NONBLOCK)", test);
204 }
205
206 static void
alloc3fds(int * s,int * sv)207 alloc3fds(int *s, int *sv)
208 {
209
210 if ((*s = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
211 err(-1, "%s: socket", test);
212 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0)
213 err(-1, "%s: socketpair", test);
214 }
215
216 static void
alloc5fds(int * s,int * sva,int * svb)217 alloc5fds(int *s, int *sva, int *svb)
218 {
219
220 if ((*s = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
221 err(-1, "%s: socket", test);
222 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sva) < 0)
223 err(-1, "%s: socketpair", test);
224 if (socketpair(PF_UNIX, SOCK_STREAM, 0, svb) < 0)
225 err(-1, "%s: socketpair", test);
226 }
227
228 static void
save_sysctls(int * before_inflight,int * before_openfiles)229 save_sysctls(int *before_inflight, int *before_openfiles)
230 {
231
232 *before_inflight = getinflight();
233 *before_openfiles = getopenfiles();
234 }
235
236 /*
237 * Try hard to make sure that the GC does in fact run before we test the
238 * condition of things.
239 */
240 static void
trigger_gc(void)241 trigger_gc(void)
242 {
243 int s;
244
245 if (forcegc) {
246 if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
247 err(-1, "trigger_gc: socket");
248 close(s);
249 }
250 sleep(1);
251 }
252
253 static void
test_sysctls(int before_inflight,int before_openfiles)254 test_sysctls(int before_inflight, int before_openfiles)
255 {
256 int after_inflight, after_openfiles;
257
258 trigger_gc();
259 after_inflight = getinflight();
260 if (after_inflight != before_inflight)
261 warnx("%s: before inflight: %d, after inflight: %d",
262 test, before_inflight, after_inflight);
263
264 after_openfiles = getopenfiles();
265 if (after_openfiles != before_openfiles)
266 warnx("%s: before: %d, after: %d", test, before_openfiles,
267 after_openfiles);
268 }
269
270 static void
twosome_nothing(void)271 twosome_nothing(void)
272 {
273 int inflight, openfiles;
274 int sv[2];
275
276 /*
277 * Create a pair, close in one order.
278 */
279 test = "twosome_nothing1";
280 printf("%s\n", test);
281 save_sysctls(&inflight, &openfiles);
282 my_socketpair(sv);
283 close2(sv[0], sv[1]);
284 test_sysctls(inflight, openfiles);
285
286 /*
287 * Create a pair, close in the other order.
288 */
289 test = "twosome_nothing2";
290 printf("%s\n", test);
291 save_sysctls(&inflight, &openfiles);
292 my_socketpair(sv);
293 close2(sv[0], sv[1]);
294 test_sysctls(inflight, openfiles);
295 }
296
297 /*
298 * Using a socket pair, send various endpoints over the pair and close in
299 * various orders.
300 */
301 static void
twosome_drop_work(const char * testname,int sendvia,int tosend,int closefirst)302 twosome_drop_work(const char *testname, int sendvia, int tosend, int closefirst)
303 {
304 int inflight, openfiles;
305 int sv[2];
306
307 printf("%s\n", testname);
308 test = testname;
309 save_sysctls(&inflight, &openfiles);
310 my_socketpair(sv);
311 sendfd(sv[sendvia], sv[tosend]);
312 if (closefirst == 0)
313 close2(sv[0], sv[1]);
314 else
315 close2(sv[1], sv[0]);
316 test_sysctls(inflight, openfiles);
317 }
318
319 static void
twosome_drop(void)320 twosome_drop(void)
321 {
322
323 /*
324 * In various combations, some wastefully symmetric, create socket
325 * pairs and send one or another endpoint over one or another
326 * endpoint, closing the endpoints in various orders.
327 */
328 twosome_drop_work("twosome_drop1", 0, 0, 0);
329 twosome_drop_work("twosome_drop2", 0, 0, 1);
330 twosome_drop_work("twosome_drop3", 0, 1, 0);
331 twosome_drop_work("twosome_drop4", 0, 1, 1);
332 twosome_drop_work("twosome_drop5", 1, 0, 0);
333 twosome_drop_work("twosome_drop6", 1, 0, 1);
334 twosome_drop_work("twosome_drop7", 1, 1, 0);
335 twosome_drop_work("twosome_drop8", 1, 1, 1);
336 }
337
338 static void
threesome_nothing(void)339 threesome_nothing(void)
340 {
341 int inflight, openfiles;
342 int s, sv[2];
343
344 test = "threesome_nothing";
345 printf("%s\n", test);
346 save_sysctls(&inflight, &openfiles);
347 alloc3fds(&s, sv);
348 close3(s, sv[0], sv[1]);
349 test_sysctls(inflight, openfiles);
350 }
351
352 /*
353 * threesome_drop: create a pair and a spare, send the spare over the pair, and
354 * close in various orders and make sure all the fds went away.
355 */
356 static void
threesome_drop(void)357 threesome_drop(void)
358 {
359 int inflight, openfiles;
360 int s, sv[2];
361
362 /*
363 * threesome_drop1: close sent send receive
364 */
365 test = "threesome_drop1";
366 printf("%s\n", test);
367 save_sysctls(&inflight, &openfiles);
368 alloc3fds(&s, sv);
369 sendfd(sv[0], s);
370 close3(s, sv[0], sv[1]);
371 test_sysctls(inflight, openfiles);
372
373 /*
374 * threesome_drop2: close sent receive send
375 */
376 test = "threesome_drop2";
377 printf("%s\n", test);
378 save_sysctls(&inflight, &openfiles);
379 alloc3fds(&s, sv);
380 sendfd(sv[0], s);
381 close3(s, sv[1], sv[0]);
382 test_sysctls(inflight, openfiles);
383
384 /*
385 * threesome_drop3: close receive sent send
386 */
387 test = "threesome_drop3";
388 printf("%s\n", test);
389 save_sysctls(&inflight, &openfiles);
390 alloc3fds(&s, sv);
391 sendfd(sv[0], s);
392 close3(sv[1], s, sv[0]);
393 test_sysctls(inflight, openfiles);
394
395 /*
396 * threesome_drop4: close receive send sent
397 */
398 test = "threesome_drop4";
399 printf("%s\n", test);
400 save_sysctls(&inflight, &openfiles);
401 alloc3fds(&s, sv);
402 sendfd(sv[0], s);
403 close3(sv[1], sv[0], s);
404 test_sysctls(inflight, openfiles);
405
406 /*
407 * threesome_drop5: close send receive sent
408 */
409 test = "threesome_drop5";
410 printf("%s\n", test);
411 save_sysctls(&inflight, &openfiles);
412 alloc3fds(&s, sv);
413 sendfd(sv[0], s);
414 close3(sv[0], sv[1], s);
415 test_sysctls(inflight, openfiles);
416
417 /*
418 * threesome_drop6: close send sent receive
419 */
420 test = "threesome_drop6";
421 printf("%s\n", test);
422 save_sysctls(&inflight, &openfiles);
423 alloc3fds(&s, sv);
424 close3(sv[0], s, sv[1]);
425 test_sysctls(inflight, openfiles);
426 }
427
428 /*
429 * Fivesome tests: create two socket pairs and a spare, send the spare over
430 * the first socket pair, then send the first socket pair over the second
431 * socket pair, and GC. Do various closes at various points to exercise
432 * various cases.
433 */
434 static void
fivesome_nothing(void)435 fivesome_nothing(void)
436 {
437 int inflight, openfiles;
438 int spare, sva[2], svb[2];
439
440 test = "fivesome_nothing";
441 printf("%s\n", test);
442 save_sysctls(&inflight, &openfiles);
443 alloc5fds(&spare, sva, svb);
444 close5(spare, sva[0], sva[1], svb[0], svb[1]);
445 test_sysctls(inflight, openfiles);
446 }
447
448 static void
fivesome_drop_work(const char * testname,int close_spare_after_send,int close_sva_after_send)449 fivesome_drop_work(const char *testname, int close_spare_after_send,
450 int close_sva_after_send)
451 {
452 int inflight, openfiles;
453 int spare, sva[2], svb[2];
454
455 printf("%s\n", testname);
456 test = testname;
457 save_sysctls(&inflight, &openfiles);
458 alloc5fds(&spare, sva, svb);
459
460 /*
461 * Send spare over sva.
462 */
463 sendfd(sva[0], spare);
464 if (close_spare_after_send)
465 close(spare);
466
467 /*
468 * Send sva over svb.
469 */
470 sendfd(svb[0], sva[0]);
471 sendfd(svb[0], sva[1]);
472 if (close_sva_after_send)
473 close2(sva[0], sva[1]);
474
475 close2(svb[0], svb[1]);
476
477 if (!close_sva_after_send)
478 close2(sva[0], sva[1]);
479 if (!close_spare_after_send)
480 close(spare);
481
482 test_sysctls(inflight, openfiles);
483 }
484
485 static void
fivesome_drop(void)486 fivesome_drop(void)
487 {
488
489 fivesome_drop_work("fivesome_drop1", 0, 0);
490 fivesome_drop_work("fivesome_drop2", 0, 1);
491 fivesome_drop_work("fivesome_drop3", 1, 0);
492 fivesome_drop_work("fivesome_drop4", 1, 1);
493 }
494
495 /*
496 * Create a somewhat nasty dual-socket socket intended to upset the garbage
497 * collector if mark-and-sweep is wrong.
498 */
499 static void
complex_cycles(void)500 complex_cycles(void)
501 {
502 int inflight, openfiles;
503 int spare, sva[2], svb[2];
504
505 test = "complex_cycles";
506 printf("%s\n", test);
507 save_sysctls(&inflight, &openfiles);
508 alloc5fds(&spare, sva, svb);
509 sendfd(sva[0], svb[0]);
510 sendfd(sva[0], svb[1]);
511 sendfd(svb[0], sva[0]);
512 sendfd(svb[0], sva[1]);
513 sendfd(svb[0], spare);
514 sendfd(sva[0], spare);
515 close5(spare, sva[0], sva[1], svb[0], svb[1]);
516 test_sysctls(inflight, openfiles);
517 }
518
519 /*
520 * Listen sockets can also be passed over UNIX domain sockets, so test
521 * various cases, including ones where listen sockets have waiting sockets
522 * hanging off them...
523 */
524 static void
listen_nothing(void)525 listen_nothing(void)
526 {
527 struct sockaddr_un sun;
528 struct sockaddr_in sin;
529 int inflight, openfiles;
530 int s;
531
532 test = "listen_nothing_unp";
533 printf("%s\n", test);
534 bzero(&sun, sizeof(sun));
535 sun.sun_family = AF_LOCAL;
536 sun.sun_len = sizeof(sun);
537 snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%s", dpath, test);
538 save_sysctls(&inflight, &openfiles);
539 s = my_socket(PF_LOCAL, SOCK_STREAM, 0);
540 my_bind(s, (struct sockaddr *)&sun, sizeof(sun));
541 my_listen(s, -1);
542 close(s);
543 (void)unlink(sun.sun_path);
544 test_sysctls(inflight, openfiles);
545
546 test = "listen_nothing_inet";
547 printf("%s\n", test);
548 bzero(&sin, sizeof(sin));
549 sin.sin_family = AF_INET;
550 sin.sin_len = sizeof(sin);
551 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
552 sin.sin_port = htons(0);
553 save_sysctls(&inflight, &openfiles);
554 s = my_socket(PF_INET, SOCK_STREAM, 0);
555 my_bind(s, (struct sockaddr *)&sin, sizeof(sin));
556 my_listen(s, -1);
557 close(s);
558 test_sysctls(inflight, openfiles);
559 }
560
561 /*
562 * Send a listen UDP socket over a UNIX domain socket.
563 *
564 * Send a listen TCP socket over a UNIX domain socket.
565 *
566 * Do each twice, with closing of the listen socket vs. socketpair in
567 * different orders.
568 */
569 static void
listen_drop(void)570 listen_drop(void)
571 {
572 struct sockaddr_un sun;
573 struct sockaddr_in sin;
574 int inflight, openfiles;
575 int s, sv[2];
576
577 bzero(&sun, sizeof(sun));
578 sun.sun_family = AF_LOCAL;
579 sun.sun_len = sizeof(sun);
580
581 /*
582 * Close listen socket first.
583 */
584 test = "listen_drop_unp1";
585 printf("%s\n", test);
586 snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%s", dpath, test);
587 save_sysctls(&inflight, &openfiles);
588 s = my_socket(PF_LOCAL, SOCK_STREAM, 0);
589 my_bind(s, (struct sockaddr *)&sun, sizeof(sun));
590 my_listen(s, -1);
591 my_socketpair(sv);
592 sendfd(sv[0], s);
593 close3(s, sv[0], sv[1]);
594 test_sysctls(inflight, openfiles);
595
596 /*
597 * Close socketpair first.
598 */
599 test = "listen_drop_unp2";
600 printf("%s\n", test);
601 snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%s", dpath, test);
602 save_sysctls(&inflight, &openfiles);
603 s = my_socket(PF_LOCAL, SOCK_STREAM, 0);
604 my_bind(s, (struct sockaddr *)&sun, sizeof(sun));
605 my_listen(s, -1);
606 my_socketpair(sv);
607 sendfd(sv[0], s);
608 close3(sv[0], sv[1], s);
609 test_sysctls(inflight, openfiles);
610
611 sin.sin_family = AF_INET;
612 sin.sin_len = sizeof(sin);
613 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
614 sin.sin_port = htons(0);
615
616 /*
617 * Close listen socket first.
618 */
619 test = "listen_drop_inet1";
620 printf("%s\n", test);
621 bzero(&sun, sizeof(sun));
622 save_sysctls(&inflight, &openfiles);
623 s = my_socket(PF_INET, SOCK_STREAM, 0);
624 my_bind(s, (struct sockaddr *)&sin, sizeof(sin));
625 my_listen(s, -1);
626 my_socketpair(sv);
627 sendfd(sv[0], s);
628 close3(s, sv[0], sv[1]);
629 test_sysctls(inflight, openfiles);
630
631 /*
632 * Close socketpair first.
633 */
634 test = "listen_drop_inet2";
635 printf("%s\n", test);
636 bzero(&sun, sizeof(sun));
637 save_sysctls(&inflight, &openfiles);
638 s = my_socket(PF_INET, SOCK_STREAM, 0);
639 my_bind(s, (struct sockaddr *)&sin, sizeof(sin));
640 my_listen(s, -1);
641 my_socketpair(sv);
642 sendfd(sv[0], s);
643 close3(sv[0], sv[1], s);
644 test_sysctls(inflight, openfiles);
645 }
646
647 /*
648 * Up things a notch with listen sockets: add connections that can be
649 * accepted to the listen queues.
650 */
651 static void
listen_connect_nothing(void)652 listen_connect_nothing(void)
653 {
654 struct sockaddr_in sin;
655 int slisten, sconnect, sv[2];
656 int inflight, openfiles;
657 socklen_t len;
658
659 test = "listen_connect_nothing";
660 printf("%s\n", test);
661 save_sysctls(&inflight, &openfiles);
662
663 slisten = my_socket(PF_INET, SOCK_STREAM, 0);
664 my_bind(slisten, (struct sockaddr *)&sin, sizeof(sin));
665 my_listen(slisten, -1);
666
667 my_socketpair(sv);
668
669 len = sizeof(sin);
670 my_getsockname(slisten, (struct sockaddr *)&sin, &len);
671
672 sconnect = my_socket(PF_INET, SOCK_STREAM, 0);
673 setnonblock(sconnect);
674 my_connect(sconnect, (struct sockaddr *)&sin, len);
675
676 sleep(1);
677
678 close4(slisten, sconnect, sv[0], sv[1]);
679
680 test_sysctls(inflight, openfiles);
681 }
682
683 static void
listen_connect_drop(void)684 listen_connect_drop(void)
685 {
686 struct sockaddr_in sin;
687 int slisten, sconnect, sv[2];
688 int inflight, openfiles;
689 socklen_t len;
690
691 test = "listen_connect_drop";
692 printf("%s\n", test);
693 save_sysctls(&inflight, &openfiles);
694
695 slisten = my_socket(PF_INET, SOCK_STREAM, 0);
696 my_bind(slisten, (struct sockaddr *)&sin, sizeof(sin));
697 my_listen(slisten, -1);
698
699 my_socketpair(sv);
700
701 len = sizeof(sin);
702 my_getsockname(slisten, (struct sockaddr *)&sin, &len);
703
704 sconnect = my_socket(PF_INET, SOCK_STREAM, 0);
705 setnonblock(sconnect);
706 my_connect(sconnect, (struct sockaddr *)&sin, len);
707
708 sleep(1);
709 sendfd(sv[0], slisten);
710 close3(slisten, sv[0], sv[1]);
711 sleep(1);
712 close(sconnect);
713
714 test_sysctls(inflight, openfiles);
715 }
716
717 static void
recursion(void)718 recursion(void)
719 {
720 int fd[2], ff[2];
721 int inflight, openfiles, deferred, deferred1;
722
723 test = "recursion";
724 printf("%s\n", test);
725 save_sysctls(&inflight, &openfiles);
726 deferred = getdeferred();
727
728 my_socketpair(fd);
729
730 for (;;) {
731 if (socketpair(PF_UNIX, SOCK_STREAM, 0, ff) == -1) {
732 if (errno == EMFILE || errno == ENFILE)
733 break;
734 err(-1, "socketpair");
735 }
736 sendfd(ff[0], fd[0]);
737 sendfd(ff[0], fd[1]);
738 close2(fd[1], fd[0]);
739 fd[0] = ff[0];
740 fd[1] = ff[1];
741 }
742 close2(fd[0], fd[1]);
743 sleep(1);
744 test_sysctls(inflight, openfiles);
745 deferred1 = getdeferred();
746 if (deferred != deferred1)
747 errx(-1, "recursion: deferred before %d after %d", deferred,
748 deferred1);
749 }
750
751 #define RMDIR "rm -Rf "
752 int
main(void)753 main(void)
754 {
755 char cmd[sizeof(RMDIR) + PATH_MAX];
756 int serrno;
757 pid_t pid;
758
759 strlcpy(dpath, "/tmp/unpgc.XXXXXXXX", sizeof(dpath));
760 if (mkdtemp(dpath) == NULL)
761 err(-1, "mkdtemp");
762
763 /*
764 * Set up a parent process to GC temporary storage when we're done.
765 */
766 pid = fork();
767 if (pid < 0) {
768 serrno = errno;
769 (void)rmdir(dpath);
770 errno = serrno;
771 err(-1, "fork");
772 }
773 if (pid > 0) {
774 signal(SIGINT, SIG_IGN);
775 while (waitpid(pid, NULL, 0) != pid);
776 snprintf(cmd, sizeof(cmd), "%s %s", RMDIR, dpath);
777 (void)system(cmd);
778 exit(0);
779 }
780
781 printf("Start: inflight %d open %d\n", getinflight(),
782 getopenfiles());
783
784 twosome_nothing();
785 twosome_drop();
786
787 threesome_nothing();
788 threesome_drop();
789
790 fivesome_nothing();
791 fivesome_drop();
792
793 complex_cycles();
794
795 listen_nothing();
796 listen_drop();
797
798 listen_connect_nothing();
799 listen_connect_drop();
800
801 recursion();
802
803 printf("Finish: inflight %d open %d\n", getinflight(),
804 getopenfiles());
805 return (0);
806 }
807