]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - tools/regression/sockets/unix_gc/unix_gc.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / tools / regression / sockets / unix_gc / unix_gc.c
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 getsysctl(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
69 static int
70 getopenfiles(void)
71 {
72
73         return (getsysctl("kern.openfiles"));
74 }
75
76 static int
77 getinflight(void)
78 {
79
80         return (getsysctl("net.local.inflight"));
81 }
82
83 static int
84 getdeferred(void)
85 {
86
87         return (getsysctl("net.local.deferred"));
88 }
89
90 static void
91 sendfd(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
117 static void
118 close2(int fd1, int fd2)
119 {
120
121         close(fd1);
122         close(fd2);
123 }
124
125 static void
126 close3(int fd1, int fd2, int fd3)
127 {
128
129         close2(fd1, fd2);
130         close(fd3);
131 }
132
133 static void
134 close4(int fd1, int fd2, int fd3, int fd4)
135 {
136
137         close2(fd1, fd2);
138         close2(fd3, fd4);
139 }
140
141 static void
142 close5(int fd1, int fd2, int fd3, int fd4, int fd5)
143 {
144
145         close3(fd1, fd2, fd3);
146         close2(fd4, fd5);
147 }
148
149 static int
150 my_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
160 static void
161 my_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
168 static void
169 my_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
176 static void
177 my_listen(int sock, int backlog)
178 {
179
180         if (listen(sock, backlog) < 0)
181                 err(-1, "%s: listen", test);
182 }
183
184 static void
185 my_socketpair(int *sv)
186 {
187
188         if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0)
189                 err(-1, "%s: socketpair", test);
190 }
191
192 static void
193 my_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
200 static void
201 setnonblock(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
208 static void
209 alloc3fds(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
218 static void
219 alloc5fds(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
230 static void
231 save_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  */
242 static void
243 trigger_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
255 static void
256 test_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
272 static void
273 twosome_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  */
303 static void
304 twosome_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
321 static void
322 twosome_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
340 static void
341 threesome_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  */
358 static void
359 threesome_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  */
436 static void
437 fivesome_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
450 static void
451 fivesome_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
487 static void
488 fivesome_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  */
501 static void
502 complex_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  */
526 static void
527 listen_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  */
571 static void
572 listen_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  */
653 static void
654 listen_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
685 static void
686 listen_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
719 static void
720 recursion(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 "
754 int
755 main(int argc, char *argv[])
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 }