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