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