]> git.ipfire.org Git - thirdparty/util-linux.git/blob - tests/helpers/test_mkfds.c
78360f7fa593409971c9cbd2db50693cbe15a025
[thirdparty/util-linux.git] / tests / helpers / test_mkfds.c
1 /*
2 * test_mkfds - make various file descriptors
3 *
4 * Written by Masatake YAMATO <yamato@redhat.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it would be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "c.h"
21 #include "xalloc.h"
22 #include "test_mkfds.h"
23 #include "exitcodes.h"
24
25 #include <arpa/inet.h>
26 #include <ctype.h>
27 #include <dirent.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <sys/file.h>
31 #include <getopt.h>
32 #include <linux/bpf.h>
33 #include <linux/if_ether.h>
34 #include <linux/if_packet.h>
35 #include <linux/if_tun.h>
36 #include <linux/netlink.h>
37 #include <linux/sockios.h> /* SIOCGSKNS */
38 #include <mqueue.h>
39 #include <net/if.h>
40 #include <netinet/in.h>
41 #include <netinet/tcp.h>
42 #include <poll.h>
43 #include <sched.h>
44 #include <signal.h>
45 #include <stdbool.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <sys/epoll.h>
50 #include <sys/eventfd.h>
51 #include <sys/inotify.h>
52 #include <sys/ioctl.h>
53 #include <sys/mman.h>
54 #include <sys/prctl.h>
55 #include <sys/select.h>
56 #include <sys/signalfd.h>
57 #include <sys/socket.h>
58 #include <sys/shm.h>
59 #include <sys/syscall.h>
60 #include <sys/timerfd.h>
61 #include <sys/types.h>
62 #include <sys/un.h>
63 #include <sys/user.h>
64 #include <sys/wait.h>
65 #include <time.h>
66 #include <unistd.h>
67
68 #define EXIT_EPERM 18
69 #define EXIT_ENOPROTOOPT 19
70 #define EXIT_EPROTONOSUPPORT 20
71 #define EXIT_EACCESS 21
72
73 #define _U_ __attribute__((__unused__))
74
75 static int pidfd_open(pid_t pid, unsigned int flags);
76 static void do_nothing(int signum _U_);
77
78 static void __attribute__((__noreturn__)) usage(FILE *out, int status)
79 {
80 fputs("\nUsage:\n", out);
81 fprintf(out, " %s [options] FACTORY FD... [PARAM=VAL...]\n", program_invocation_short_name);
82
83 fputs("\nOptions:\n", out);
84 fputs(" -l, --list list available file descriptor factories and exit\n", out);
85 fputs(" -I, --parameters <factory> list parameters the factory takes\n", out);
86 fputs(" -r, --comm <name> rename self\n", out);
87 fputs(" -q, --quiet don't print pid(s)\n", out);
88 fputs(" -X, --dont-monitor-stdin don't monitor stdin when pausing\n", out);
89 fputs(" -c, --dont-pause don't pause after making fd(s)\n", out);
90 fputs(" -w, --wait-with <multiplexer> use MULTIPLEXER for waiting events\n", out);
91 fputs(" -W, --multiplexers list multiplexers\n", out);
92
93 fputs("\n", out);
94 fputs("Examples:\n", out);
95 fprintf(out, "Using 3, open /etc/group:\n\n $ %s ro-regular-file 3 file=/etc/group\n\n",
96 program_invocation_short_name);
97 fprintf(out, "Using 3 and 4, make a pipe:\n\n $ %s pipe-no-fork 3 4\n\n",
98 program_invocation_short_name);
99
100 exit(status);
101 }
102
103 union value {
104 const char *string;
105 long integer;
106 unsigned long uinteger;
107 bool boolean;
108 };
109
110 enum ptype {
111 PTYPE_STRING,
112 PTYPE_INTEGER,
113 PTYPE_UINTEGER,
114 PTYPE_BOOLEAN,
115 };
116
117 struct ptype_class {
118 const char *name;
119
120 /* Covert to a string representation.
121 * A caller must free the returned value with free(3) after using. */
122 char *(*sprint)(const union value *value);
123
124 /* Convert from a string. If ARG is NULL, use DEFV instead.
125 * A caller must free the returned value with the free method
126 * after using. */
127 union value (*read)(const char *arg, const union value *defv);
128
129 /* Free the value returned from the read method. */
130 void (*free)(union value value);
131 };
132
133 #define ARG_STRING(A) (A.v.string)
134 #define ARG_INTEGER(A) (A.v.integer)
135 #define ARG_UINTEGER(A) (A.v.uinteger)
136 #define ARG_BOOLEAN(A) (A.v.boolean)
137 struct arg {
138 union value v;
139 void (*free)(union value value);
140 };
141
142 struct parameter {
143 const char *name;
144 const enum ptype type;
145 const char *desc;
146 union value defv; /* Default value */
147 };
148
149 static char *string_sprint(const union value *value)
150 {
151 return xstrdup(value->string);
152 }
153
154 static union value string_read(const char *arg, const union value *defv)
155 {
156 return (union value){ .string = xstrdup(arg?: defv->string) };
157 }
158
159 static void string_free(union value value)
160 {
161 free((void *)value.string);
162 }
163
164 static char *integer_sprint(const union value *value)
165 {
166 char *str = NULL;
167 xasprintf(&str, "%ld", value->integer);
168 return str;
169 }
170
171 static union value integer_read(const char *arg, const union value *defv)
172 {
173 char *ep;
174 union value r;
175
176 if (!arg)
177 return *defv;
178
179 errno = 0;
180 r.integer = strtol(arg, &ep, 10);
181 if (errno)
182 err(EXIT_FAILURE, "fail to make a number from %s", arg);
183 else if (*ep != '\0')
184 errx(EXIT_FAILURE, "garbage at the end of number: %s", arg);
185 return r;
186 }
187
188 static void integer_free(union value value _U_)
189 {
190 /* Do nothing */
191 }
192
193 static char *uinteger_sprint(const union value *value)
194 {
195 char *str = NULL;
196 xasprintf(&str, "%lu", value->uinteger);
197 return str;
198 }
199
200 static union value uinteger_read(const char *arg, const union value *defv)
201 {
202 char *ep;
203 union value r;
204
205 if (!arg)
206 return *defv;
207
208 errno = 0;
209 r.uinteger = strtoul(arg, &ep, 10);
210 if (errno)
211 err(EXIT_FAILURE, "fail to make a number from %s", arg);
212 else if (*ep != '\0')
213 errx(EXIT_FAILURE, "garbage at the end of number: %s", arg);
214 return r;
215 }
216
217 static void uinteger_free(union value value _U_)
218 {
219 /* Do nothing */
220 }
221
222 static char *boolean_sprint(const union value *value)
223 {
224 return xstrdup(value->boolean? "true": "false");
225 }
226
227 static union value boolean_read(const char *arg, const union value *defv)
228 {
229 union value r;
230
231 if (!arg)
232 return *defv;
233
234 if (strcasecmp(arg, "true") == 0
235 || strcmp(arg, "1") == 0
236 || strcasecmp(arg, "yes") == 0
237 || strcasecmp(arg, "y") == 0)
238 r.boolean = true;
239 else
240 r.boolean = false;
241 return r;
242 }
243
244 static void boolean_free(union value value _U_)
245 {
246 /* Do nothing */
247 }
248
249 struct ptype_class ptype_classes [] = {
250 [PTYPE_STRING] = {
251 .name = "string",
252 .sprint = string_sprint,
253 .read = string_read,
254 .free = string_free,
255 },
256 [PTYPE_INTEGER] = {
257 .name = "integer",
258 .sprint = integer_sprint,
259 .read = integer_read,
260 .free = integer_free,
261 },
262 [PTYPE_UINTEGER] = {
263 .name = "uinteger",
264 .sprint = uinteger_sprint,
265 .read = uinteger_read,
266 .free = uinteger_free,
267 },
268 [PTYPE_BOOLEAN] = {
269 .name = "boolean",
270 .sprint = boolean_sprint,
271 .read = boolean_read,
272 .free = boolean_free,
273 },
274 };
275
276 static struct arg decode_arg(const char *pname,
277 const struct parameter *parameters,
278 int argc, char **argv)
279 {
280 char *v = NULL;
281 size_t len = strlen(pname);
282 const struct parameter *p = NULL;
283 struct arg arg;
284
285 while (parameters->name) {
286 if (strcmp(pname, parameters->name) == 0) {
287 p = parameters;
288 break;
289 }
290 parameters++;
291 }
292 if (p == NULL)
293 errx(EXIT_FAILURE, "no such parameter: %s", pname);
294
295 for (int i = 0; i < argc; i++) {
296 if (strncmp(pname, argv[i], len) == 0) {
297 v = argv[i] + len;
298 if (*v == '=') {
299 v++;
300 break;
301 } else if (*v == '\0')
302 errx(EXIT_FAILURE,
303 "no value given for \"%s\" parameter",
304 pname);
305 else
306 v = NULL;
307 }
308 }
309 arg.v = ptype_classes [p->type].read (v, &p->defv);
310 arg.free = ptype_classes [p->type].free;
311 return arg;
312 }
313
314 static void free_arg(struct arg *arg)
315 {
316 arg->free(arg->v);
317 }
318
319 struct factory {
320 const char *name; /* [-a-zA-Z0-9_]+ */
321 const char *desc;
322 bool priv; /* the root privilege is needed to make fd(s) */
323 #define MAX_N 13
324 int N; /* the number of fds this factory makes */
325 int EX_N; /* fds made optionally */
326 int EX_R; /* the number of extra words printed to stdout. */
327 void *(*make)(const struct factory *, struct fdesc[], int, char **);
328 void (*free)(const struct factory *, void *);
329 void (*report)(const struct factory *, int, void *, FILE *);
330 const struct parameter * params;
331 };
332
333 static void close_fdesc(int fd, void *data _U_)
334 {
335 close(fd);
336 }
337
338 volatile ssize_t unused_result_ok;
339 static void abort_with_child_death_message(int signum _U_)
340 {
341 const char msg[] = "the child process exits unexpectedly";
342 unused_result_ok = write(2, msg, sizeof(msg));
343 _exit(EXIT_FAILURE);
344 }
345
346 static void *open_ro_regular_file(const struct factory *factory, struct fdesc fdescs[],
347 int argc, char ** argv)
348 {
349 struct arg file = decode_arg("file", factory->params, argc, argv);
350 struct arg offset = decode_arg("offset", factory->params, argc, argv);
351 struct arg lease_r = decode_arg("read-lease", factory->params, argc, argv);
352
353 int fd = open(ARG_STRING(file), O_RDONLY);
354 if (fd < 0)
355 err(EXIT_FAILURE, "failed to open: %s", ARG_STRING(file));
356 free_arg(&file);
357
358 if (ARG_INTEGER(offset) != 0) {
359 if (lseek(fd, (off_t)ARG_INTEGER(offset), SEEK_CUR) < 0) {
360 int e = errno;
361 close(fd);
362 errno = e;
363 err(EXIT_FAILURE, "failed to seek 0 -> %ld", ARG_INTEGER(offset));
364 }
365 }
366 free_arg(&offset);
367
368 if (ARG_BOOLEAN(lease_r)) {
369 if (fcntl(fd, F_SETLEASE, F_RDLCK) < 0) {
370 int e = errno;
371 close(fd);
372 errno = e;
373 err(EXIT_FAILURE, "failed to take out a read lease");
374 }
375 }
376 free_arg(&lease_r);
377
378 if (fd != fdescs[0].fd) {
379 if (dup2(fd, fdescs[0].fd) < 0) {
380 int e = errno;
381 close(fd);
382 errno = e;
383 err(EXIT_FAILURE, "failed to dup %d -> %d", fd, fdescs[0].fd);
384 }
385 close(fd);
386 }
387
388 fdescs[0] = (struct fdesc){
389 .fd = fdescs[0].fd,
390 .close = close_fdesc,
391 .data = NULL
392 };
393
394 return NULL;
395 }
396
397 static void unlink_and_close_fdesc(int fd, void *data)
398 {
399 char *fname = data;
400
401 unlink(fname);
402 close(fd);
403 }
404
405 typedef void (*lockFn)(int fd, const char *fname, int dupfd);
406
407 static void lock_fn_none(int fd _U_, const char *fname _U_, int dupfd _U_)
408 {
409 /* Do nothing */
410 }
411
412 static void lock_fn_flock_sh(int fd, const char *fname, int dupfd)
413 {
414 if (flock(fd, LOCK_SH) < 0) {
415 int e = errno;
416 close(fd);
417 close(dupfd);
418 if (fname)
419 unlink(fname);
420 errno = e;
421 err(EXIT_FAILURE, "failed to lock");
422 }
423 }
424
425 static void lock_fn_flock_ex(int fd, const char *fname, int dupfd)
426 {
427 if (flock(fd, LOCK_EX) < 0) {
428 int e = errno;
429 close(fd);
430 close(dupfd);
431 if (fname)
432 unlink(fname);
433 errno = e;
434 err(EXIT_FAILURE, "failed to lock");
435 }
436 }
437
438 static void lock_fn_posix_r_(int fd, const char *fname, int dupfd)
439 {
440 struct flock r = {
441 .l_type = F_RDLCK,
442 .l_whence = SEEK_SET,
443 .l_start = 0,
444 .l_len = 1,
445 };
446 if (fcntl(fd, F_SETLK, &r) < 0) {
447 int e = errno;
448 close(fd);
449 close(dupfd);
450 if (fname)
451 unlink(fname);
452 errno = e;
453 err(EXIT_FAILURE, "failed to lock");
454 }
455 }
456
457 static void lock_fn_posix__w(int fd, const char *fname, int dupfd)
458 {
459 struct flock w = {
460 .l_type = F_WRLCK,
461 .l_whence = SEEK_SET,
462 .l_start = 0,
463 .l_len = 1,
464 };
465 if (fcntl(fd, F_SETLK, &w) < 0) {
466 int e = errno;
467 close(fd);
468 close(dupfd);
469 if (fname)
470 unlink(fname);
471 errno = e;
472 err(EXIT_FAILURE, "failed to lock");
473 }
474 }
475
476 static void lock_fn_posix_rw(int fd, const char *fname, int dupfd)
477 {
478 struct flock r = {
479 .l_type = F_RDLCK,
480 .l_whence = SEEK_SET,
481 .l_start = 0,
482 .l_len = 1,
483 };
484 struct flock w = {
485 .l_type = F_WRLCK,
486 .l_whence = SEEK_SET,
487 .l_start = 2,
488 .l_len = 1,
489 };
490 if (fcntl(fd, F_SETLK, &r) < 0) {
491 int e = errno;
492 close(fd);
493 close(dupfd);
494 if (fname)
495 unlink(fname);
496 errno = e;
497 err(EXIT_FAILURE, "failed to lock(read)");
498 }
499 if (fcntl(fd, F_SETLK, &w) < 0) {
500 int e = errno;
501 close(fd);
502 close(dupfd);
503 if (fname)
504 unlink(fname);
505 errno = e;
506 err(EXIT_FAILURE, "failed to lock(write)");
507 }
508 }
509
510 static void lock_fn_ofd_r_(int fd, const char *fname, int dupfd)
511 {
512 struct flock r = {
513 .l_type = F_RDLCK,
514 .l_whence = SEEK_SET,
515 .l_start = 0,
516 .l_len = 1,
517 .l_pid = 0,
518 };
519 if (fcntl(fd, F_OFD_SETLK, &r) < 0) {
520 int e = errno;
521 close(fd);
522 close(dupfd);
523 if (fname)
524 unlink(fname);
525 errno = e;
526 err(EXIT_FAILURE, "failed to lock");
527 }
528 }
529
530 static void lock_fn_ofd__w(int fd, const char *fname, int dupfd)
531 {
532 struct flock w = {
533 .l_type = F_WRLCK,
534 .l_whence = SEEK_SET,
535 .l_start = 0,
536 .l_len = 1,
537 .l_pid = 0,
538 };
539 if (fcntl(fd, F_OFD_SETLK, &w) < 0) {
540 int e = errno;
541 close(fd);
542 close(dupfd);
543 if (fname)
544 unlink(fname);
545 errno = e;
546 err(EXIT_FAILURE, "failed to lock");
547 }
548 }
549
550 static void lock_fn_ofd_rw(int fd, const char *fname, int dupfd)
551 {
552 struct flock r = {
553 .l_type = F_RDLCK,
554 .l_whence = SEEK_SET,
555 .l_start = 0,
556 .l_len = 1,
557 .l_pid = 0,
558 };
559 struct flock w = {
560 .l_type = F_WRLCK,
561 .l_whence = SEEK_SET,
562 .l_start = 2,
563 .l_len = 1,
564 .l_pid = 0,
565 };
566 if (fcntl(fd, F_OFD_SETLK, &r) < 0) {
567 int e = errno;
568 close(fd);
569 close(dupfd);
570 if (fname)
571 unlink(fname);
572 errno = e;
573 err(EXIT_FAILURE, "failed to lock(read)");
574 }
575 if (fcntl(fd, F_OFD_SETLK, &w) < 0) {
576 int e = errno;
577 close(fd);
578 close(dupfd);
579 if (fname)
580 unlink(fname);
581 errno = e;
582 err(EXIT_FAILURE, "failed to lock(write)");
583 }
584 }
585
586 static void lock_fn_lease_w(int fd, const char *fname, int dupfd)
587 {
588 if (fcntl(fd, F_SETLEASE, F_WRLCK) < 0) {
589 int e = errno;
590 close(fd);
591 close(dupfd);
592 if (fname)
593 unlink(fname);
594 errno = e;
595 err(EXIT_FAILURE, "failed to take out a write lease");
596 }
597 }
598
599
600 static void *make_w_regular_file(const struct factory *factory, struct fdesc fdescs[],
601 int argc, char ** argv)
602 {
603 int fd;
604
605 struct arg file = decode_arg("file", factory->params, argc, argv);
606 char *fname = xstrdup(ARG_STRING(file));
607
608 struct arg delete = decode_arg("delete", factory->params, argc, argv);
609 bool bDelete = ARG_BOOLEAN(delete);
610
611 struct arg write_bytes = decode_arg("write-bytes", factory->params, argc, argv);
612 int iWrite_bytes = ARG_INTEGER(write_bytes);
613
614 struct arg readable = decode_arg("readable", factory->params, argc, argv);
615 bool bReadable = ARG_BOOLEAN(readable);
616
617 struct arg lock = decode_arg("lock", factory->params, argc, argv);
618 const char *sLock = ARG_STRING(lock);
619 lockFn lock_fn;
620
621 struct arg dupfd = decode_arg("dupfd", factory->params, argc, argv);
622 int iDupfd = ARG_INTEGER(dupfd);
623
624 void *data = NULL;
625
626 if (iWrite_bytes < 0)
627 errx(EXIT_FAILURE, "write-bytes must be a positive number or zero.");
628
629 if (strcmp(sLock, "none") == 0)
630 lock_fn = lock_fn_none;
631 else if (strcmp(sLock, "flock-sh") == 0)
632 lock_fn = lock_fn_flock_sh;
633 else if (strcmp(sLock, "flock-ex") == 0)
634 lock_fn = lock_fn_flock_ex;
635 else if (strcmp(sLock, "posix-r-") == 0) {
636 bReadable = true;
637 if (iWrite_bytes < 1)
638 iWrite_bytes = 1;
639 lock_fn = lock_fn_posix_r_;
640 } else if (strcmp(sLock, "posix--w") == 0) {
641 if (iWrite_bytes < 1)
642 iWrite_bytes = 1;
643 lock_fn = lock_fn_posix__w;
644 } else if (strcmp(sLock, "posix-rw") == 0) {
645 bReadable = true;
646 if (iWrite_bytes < 3)
647 iWrite_bytes = 3;
648 lock_fn = lock_fn_posix_rw;
649 } else if (strcmp(sLock, "ofd-r-") == 0) {
650 bReadable = true;
651 if (iWrite_bytes < 1)
652 iWrite_bytes = 1;
653 lock_fn = lock_fn_ofd_r_;
654 } else if (strcmp(sLock, "ofd--w") == 0) {
655 if (iWrite_bytes < 1)
656 iWrite_bytes = 1;
657 lock_fn = lock_fn_ofd__w;
658 } else if (strcmp(sLock, "ofd-rw") == 0) {
659 bReadable = true;
660 if (iWrite_bytes < 3)
661 iWrite_bytes = 3;
662 lock_fn = lock_fn_ofd_rw;
663 } else if (strcmp(sLock, "lease-w") == 0)
664 lock_fn = lock_fn_lease_w;
665 else
666 errx(EXIT_FAILURE, "unexpected value for lock parameter: %s", sLock);
667
668 free_arg(&dupfd);
669 free_arg(&lock);
670 free_arg(&readable);
671 free_arg(&write_bytes);
672 free_arg(&delete);
673 free_arg(&file);
674
675 fd = open(fname, O_CREAT|O_EXCL|(bReadable? O_RDWR: O_WRONLY), S_IWUSR);
676 if (fd < 0)
677 err(EXIT_FAILURE, "failed to make: %s", fname);
678
679 if (fd != fdescs[0].fd) {
680 if (dup2(fd, fdescs[0].fd) < 0) {
681 int e = errno;
682 close(fd);
683 unlink(fname);
684 free (fname);
685 errno = e;
686 err(EXIT_FAILURE, "failed to dup %d -> %d", fd, fdescs[0].fd);
687 }
688 close(fd);
689 fd = fdescs[0].fd;
690 }
691
692 if (bDelete) {
693 if (unlink(fname) < 0) {
694 int e = errno;
695 close(fd);
696 errno = e;
697 err(EXIT_FAILURE, "failed to unlink %s", fname);
698 }
699 free(fname);
700 fname = NULL;
701 }
702
703 for (int i = 0; i < iWrite_bytes; i++) {
704 if (write(fd, "z", 1) != 1) {
705 int e = errno;
706 close(fd);
707 if (fname)
708 unlink(fname);
709 errno = e;
710 err(EXIT_FAILURE, "failed to write");
711 }
712 }
713
714 if (iDupfd >= 0) {
715 if (dup2(fd, iDupfd) < 0) {
716 int e = errno;
717 close(fd);
718 if (fname)
719 unlink(fname);
720 errno = e;
721 err(EXIT_FAILURE, "failed in dup2");
722 }
723 data = xmalloc(sizeof (iDupfd));
724 *((int *)data) = iDupfd;
725 }
726
727 lock_fn(fd, fname, iDupfd);
728
729 fdescs[0] = (struct fdesc){
730 .fd = fdescs[0].fd,
731 .close = bDelete? close_fdesc: unlink_and_close_fdesc,
732 .data = fname,
733 };
734
735 return data;
736 }
737
738 static void free_after_closing_duplicated_fd(const struct factory * factory _U_, void *data)
739 {
740 if (data) {
741 int *fdp = data;
742 close(*fdp);
743 free (data);
744 }
745 }
746
747 static void *make_pipe(const struct factory *factory, struct fdesc fdescs[],
748 int argc, char ** argv)
749 {
750 int pd[2];
751 int nonblock_flags[2] = {0, 0};
752 struct arg nonblock = decode_arg("nonblock", factory->params, argc, argv);
753 if (strlen(ARG_STRING(nonblock)) != 2) {
754 errx(EXIT_FAILURE, "string value for %s has unexpected length: %s",
755 "nonblock", ARG_STRING(nonblock));
756 }
757
758 /* Make extra pipe descriptors for making pipe objects connected
759 * with fds more than 2.
760 * See https://github.com/util-linux/util-linux/pull/1622
761 * about the background of the requirement. */
762 struct arg rdup = decode_arg("rdup", factory->params, argc, argv);
763 struct arg wdup = decode_arg("wdup", factory->params, argc, argv);
764 int xpd[2];
765 xpd [0] = ARG_INTEGER(rdup);
766 xpd [1] = ARG_INTEGER(wdup);
767
768 for (int i = 0; i < 2; i++) {
769 if (ARG_STRING(nonblock)[i] == '-')
770 continue;
771 if ((i == 0 && ARG_STRING(nonblock)[i] == 'r')
772 || (i == 1 && ARG_STRING(nonblock)[i] == 'w'))
773 nonblock_flags[i] = 1;
774 else
775 errx(EXIT_FAILURE, "unexpected value %c for the %s fd of %s",
776 ARG_STRING(nonblock)[i],
777 (i == 0)? "read": "write",
778 "nonblock");
779 }
780 free_arg(&nonblock);
781
782 if (pipe(pd) < 0)
783 err(EXIT_FAILURE, "failed to make pipe");
784
785 for (int i = 0; i < 2; i++) {
786 if (nonblock_flags[i]) {
787 int flags = fcntl(pd[i], F_GETFL);
788 if (fcntl(pd[i], F_SETFL, flags|O_NONBLOCK) < 0) {
789 int e = errno;
790 close(pd[0]);
791 close(pd[1]);
792 errno = e;
793 errx(EXIT_FAILURE, "failed to set NONBLOCK flag to the %s fd",
794 (i == 0)? "read": "write");
795 }
796 }
797 }
798
799 for (int i = 0; i < 2; i++) {
800 if (pd[i] != fdescs[i].fd) {
801 if (dup2(pd[i], fdescs[i].fd) < 0) {
802 int e = errno;
803 close(pd[0]);
804 close(pd[1]);
805 errno = e;
806 err(EXIT_FAILURE, "failed to dup %d -> %d",
807 pd[i], fdescs[i].fd);
808 }
809 close(pd[i]);
810 }
811 fdescs[i] = (struct fdesc){
812 .fd = fdescs[i].fd,
813 .close = close_fdesc,
814 .data = NULL
815 };
816 }
817
818 /* Make extra pipe descriptors. */
819 for (int i = 0; i < 2; i++) {
820 if (xpd[i] >= 0) {
821 if (dup2(fdescs[i].fd, xpd[i]) < 0) {
822 int e = errno;
823 close(fdescs[0].fd);
824 close(fdescs[1].fd);
825 if (i > 0 && xpd[0] >= 0)
826 close(xpd[0]);
827 errno = e;
828 err(EXIT_FAILURE, "failed to dup %d -> %d",
829 fdescs[i].fd, xpd[i]);
830 }
831 fdescs[i + 2] = (struct fdesc){
832 .fd = xpd[i],
833 .close = close_fdesc,
834 .data = NULL
835 };
836 }
837 }
838
839 return NULL;
840 }
841
842 static void close_dir(int fd, void *data)
843 {
844 DIR *dp = data;
845 if (dp)
846 closedir(dp);
847 else
848 close_fdesc(fd, NULL);
849 }
850
851 static void *open_directory(const struct factory *factory, struct fdesc fdescs[],
852 int argc, char ** argv)
853 {
854 struct arg dir = decode_arg("dir", factory->params, argc, argv);
855 struct arg dentries = decode_arg("dentries", factory->params, argc, argv);
856 DIR *dp = NULL;
857
858 int fd = open(ARG_STRING(dir), O_RDONLY|O_DIRECTORY);
859 if (fd < 0)
860 err(EXIT_FAILURE, "failed to open: %s", ARG_STRING(dir));
861 free_arg(&dir);
862
863 if (fd != fdescs[0].fd) {
864 if (dup2(fd, fdescs[0].fd) < 0) {
865 int e = errno;
866 close(fd);
867 errno = e;
868 err(EXIT_FAILURE, "failed to dup %d -> %d", fd, fdescs[0].fd);
869 }
870 close(fd);
871 }
872
873 if (ARG_INTEGER(dentries) > 0) {
874 dp = fdopendir(fdescs[0].fd);
875 if (dp == NULL) {
876 int e = errno;
877 close(fdescs[0].fd);
878 errno = e;
879 err(EXIT_FAILURE, "failed to make DIR* from fd: %s", ARG_STRING(dir));
880 }
881 for (int i = 0; i < ARG_INTEGER(dentries); i++) {
882 struct dirent *d = readdir(dp);
883 if (!d) {
884 int e = errno;
885 closedir(dp);
886 errno = e;
887 err(EXIT_FAILURE, "failed in readdir(3)");
888 }
889 }
890 }
891 free_arg(&dentries);
892
893 fdescs[0] = (struct fdesc){
894 .fd = fdescs[0].fd,
895 .close = close_dir,
896 .data = dp
897 };
898
899 return NULL;
900 }
901
902 static void *open_rw_chrdev(const struct factory *factory, struct fdesc fdescs[],
903 int argc, char ** argv)
904 {
905 struct arg chrdev = decode_arg("chrdev", factory->params, argc, argv);
906 int fd = open(ARG_STRING(chrdev), O_RDWR);
907 if (fd < 0)
908 err(EXIT_FAILURE, "failed to open: %s", ARG_STRING(chrdev));
909 free_arg(&chrdev);
910
911 if (fd != fdescs[0].fd) {
912 if (dup2(fd, fdescs[0].fd) < 0) {
913 int e = errno;
914 close(fd);
915 errno = e;
916 err(EXIT_FAILURE, "failed to dup %d -> %d", fd, fdescs[0].fd);
917 }
918 close(fd);
919 }
920
921 fdescs[0] = (struct fdesc){
922 .fd = fdescs[0].fd,
923 .close = close_fdesc,
924 .data = NULL
925 };
926
927 return NULL;
928 }
929
930 static void *make_socketpair(const struct factory *factory, struct fdesc fdescs[],
931 int argc, char ** argv)
932 {
933 int sd[2];
934 struct arg socktype = decode_arg("socktype", factory->params, argc, argv);
935 int isocktype;
936 struct arg halfclose = decode_arg("halfclose", factory->params, argc, argv);
937 bool bhalfclose;
938
939 bhalfclose = ARG_BOOLEAN(halfclose);
940 free_arg(&halfclose);
941
942 if (strcmp(ARG_STRING(socktype), "STREAM") == 0)
943 isocktype = SOCK_STREAM;
944 else if (strcmp(ARG_STRING(socktype), "DGRAM") == 0)
945 isocktype = SOCK_DGRAM;
946 else if (strcmp(ARG_STRING(socktype), "SEQPACKET") == 0)
947 isocktype = SOCK_SEQPACKET;
948 else
949 errx(EXIT_FAILURE,
950 "unknown socket type for socketpair(AF_UNIX,...): %s",
951 ARG_STRING(socktype));
952 free_arg(&socktype);
953
954 if (socketpair(AF_UNIX, isocktype, 0, sd) < 0)
955 err(EXIT_FAILURE, "failed to make socket pair");
956
957 if (bhalfclose) {
958 if (shutdown(sd[0], SHUT_RD) < 0)
959 err(EXIT_FAILURE,
960 "failed to shutdown the read end of the 1st socket");
961 if (shutdown(sd[1], SHUT_WR) < 0)
962 err(EXIT_FAILURE,
963 "failed to shutdown the write end of the 2nd socket");
964 }
965
966 for (int i = 0; i < 2; i++) {
967 if (sd[i] != fdescs[i].fd) {
968 if (dup2(sd[i], fdescs[i].fd) < 0) {
969 int e = errno;
970 close(sd[0]);
971 close(sd[1]);
972 errno = e;
973 err(EXIT_FAILURE, "failed to dup %d -> %d",
974 sd[i], fdescs[i].fd);
975 }
976 close(sd[i]);
977 }
978 fdescs[i] = (struct fdesc){
979 .fd = fdescs[i].fd,
980 .close = close_fdesc,
981 .data = NULL
982 };
983 }
984
985 return NULL;
986 }
987
988 static void *open_with_opath(const struct factory *factory, struct fdesc fdescs[],
989 int argc, char ** argv)
990 {
991 struct arg path = decode_arg("path", factory->params, argc, argv);
992 int fd = open(ARG_STRING(path), O_PATH|O_NOFOLLOW);
993 if (fd < 0)
994 err(EXIT_FAILURE, "failed to open with O_PATH: %s", ARG_STRING(path));
995 free_arg(&path);
996
997 if (fd != fdescs[0].fd) {
998 if (dup2(fd, fdescs[0].fd) < 0) {
999 int e = errno;
1000 close(fd);
1001 errno = e;
1002 err(EXIT_FAILURE, "failed to dup %d -> %d", fd, fdescs[0].fd);
1003 }
1004 close(fd);
1005 }
1006
1007 fdescs[0] = (struct fdesc){
1008 .fd = fdescs[0].fd,
1009 .close = close_fdesc,
1010 .data = NULL
1011 };
1012
1013 return NULL;
1014 }
1015
1016 static void *open_ro_blkdev(const struct factory *factory, struct fdesc fdescs[],
1017 int argc, char ** argv)
1018 {
1019 struct arg blkdev = decode_arg("blkdev", factory->params, argc, argv);
1020 int fd = open(ARG_STRING(blkdev), O_RDONLY);
1021 if (fd < 0)
1022 err(EXIT_FAILURE, "failed to open: %s", ARG_STRING(blkdev));
1023 free_arg(&blkdev);
1024
1025 if (fd != fdescs[0].fd) {
1026 if (dup2(fd, fdescs[0].fd) < 0) {
1027 int e = errno;
1028 close(fd);
1029 errno = e;
1030 err(EXIT_FAILURE, "failed to dup %d -> %d", fd, fdescs[0].fd);
1031 }
1032 close(fd);
1033 }
1034
1035 fdescs[0] = (struct fdesc){
1036 .fd = fdescs[0].fd,
1037 .close = close_fdesc,
1038 .data = NULL,
1039 };
1040
1041 return NULL;
1042 }
1043
1044 static int make_packet_socket(int socktype, const char *interface)
1045 {
1046 int sd;
1047 struct sockaddr_ll addr;
1048
1049 sd = socket(AF_PACKET, socktype, htons(ETH_P_ALL));
1050 if (sd < 0)
1051 err(EXIT_FAILURE, "failed to make a socket with AF_PACKET");
1052
1053 if (interface == NULL)
1054 return sd; /* Just making a socket */
1055
1056 memset(&addr, 0, sizeof(struct sockaddr_ll));
1057 addr.sll_family = AF_PACKET;
1058 addr.sll_ifindex = if_nametoindex(interface);
1059 if (addr.sll_ifindex == 0) {
1060 int e = errno;
1061 close(sd);
1062 errno = e;
1063 err(EXIT_FAILURE,
1064 "failed to get the interface index for %s", interface);
1065 }
1066 if (bind(sd, (struct sockaddr *)&addr, sizeof(struct sockaddr_ll)) < 0) {
1067 int e = errno;
1068 close(sd);
1069 errno = e;
1070 err(EXIT_FAILURE,
1071 "failed to get the interface index for %s", interface);
1072 }
1073
1074 return sd;
1075 }
1076
1077 struct munmap_data {
1078 void *ptr;
1079 size_t len;
1080 };
1081
1082 static void close_fdesc_after_munmap(int fd, void *data)
1083 {
1084 struct munmap_data *munmap_data = data;
1085 munmap(munmap_data->ptr, munmap_data->len);
1086 free(data);
1087 close(fd);
1088 }
1089
1090 static void *make_mmapped_packet_socket(const struct factory *factory, struct fdesc fdescs[],
1091 int argc, char ** argv)
1092 {
1093 int sd;
1094 struct arg socktype = decode_arg("socktype", factory->params, argc, argv);
1095 struct arg interface = decode_arg("interface", factory->params, argc, argv);
1096
1097 int isocktype;
1098 const char *sinterface;
1099 struct tpacket_req req;
1100 struct munmap_data *munmap_data;
1101
1102 if (strcmp(ARG_STRING(socktype), "DGRAM") == 0)
1103 isocktype = SOCK_DGRAM;
1104 else if (strcmp(ARG_STRING(socktype), "RAW") == 0)
1105 isocktype = SOCK_RAW;
1106 else
1107 errx(EXIT_FAILURE,
1108 "unknown socket type for socket(AF_PACKET,...): %s",
1109 ARG_STRING(socktype));
1110 free_arg(&socktype);
1111
1112 sinterface = ARG_STRING(interface);
1113 sd = make_packet_socket(isocktype, sinterface);
1114 free_arg(&interface);
1115
1116 /* Specify the spec of ring buffers.
1117 *
1118 * ref.
1119 * - linux/Documentation/networking/packet_mmap.rst
1120 * - https://sites.google.com/site/packetmmap/home
1121 */
1122 req.tp_block_size = getpagesize();
1123 req.tp_frame_size = getpagesize();
1124 req.tp_block_nr = 1;
1125 req.tp_frame_nr = 1;
1126 if (setsockopt(sd, SOL_PACKET, PACKET_TX_RING, (char *)&req, sizeof(req)) < 0) {
1127 int e = errno;
1128 close(sd);
1129 errno = e;
1130 err((errno == ENOPROTOOPT? EXIT_ENOPROTOOPT: EXIT_FAILURE),
1131 "failed to specify a buffer spec to a packet socket");
1132 }
1133
1134 munmap_data = xmalloc(sizeof (*munmap_data));
1135 munmap_data->len = (size_t) req.tp_block_size * req.tp_block_nr;
1136 munmap_data->ptr = mmap(NULL, munmap_data->len, PROT_WRITE, MAP_SHARED, sd, 0);
1137 if (munmap_data->ptr == MAP_FAILED) {
1138 int e = errno;
1139 close(sd);
1140 free(munmap_data);
1141 errno = e;
1142 err(EXIT_FAILURE, "failed to do mmap a packet socket");
1143 }
1144
1145 if (sd != fdescs[0].fd) {
1146 if (dup2(sd, fdescs[0].fd) < 0) {
1147 int e = errno;
1148 close(sd);
1149 munmap(munmap_data->ptr, munmap_data->len);
1150 free(munmap_data);
1151 errno = e;
1152 err(EXIT_FAILURE, "failed to dup %d -> %d", sd, fdescs[0].fd);
1153 }
1154 close(sd);
1155 }
1156
1157 fdescs[0] = (struct fdesc){
1158 .fd = fdescs[0].fd,
1159 .close = close_fdesc_after_munmap,
1160 .data = munmap_data,
1161 };
1162
1163 return NULL;
1164 }
1165
1166 static void *make_pidfd(const struct factory *factory, struct fdesc fdescs[],
1167 int argc, char ** argv)
1168 {
1169 struct arg target_pid = decode_arg("target-pid", factory->params, argc, argv);
1170 pid_t pid = ARG_INTEGER(target_pid);
1171
1172 int fd = pidfd_open(pid, 0);
1173 if (fd < 0)
1174 err_nosys(EXIT_FAILURE, "failed in pidfd_open(%d)", (int)pid);
1175 free_arg(&target_pid);
1176
1177 if (fd != fdescs[0].fd) {
1178 if (dup2(fd, fdescs[0].fd) < 0) {
1179 int e = errno;
1180 close(fd);
1181 errno = e;
1182 err(EXIT_FAILURE, "failed to dup %d -> %d", fd, fdescs[0].fd);
1183 }
1184 close(fd);
1185 }
1186
1187 fdescs[0] = (struct fdesc){
1188 .fd = fdescs[0].fd,
1189 .close = close_fdesc,
1190 .data = NULL
1191 };
1192
1193 return NULL;
1194 }
1195
1196 static void *make_inotify_fd(const struct factory *factory _U_, struct fdesc fdescs[],
1197 int argc _U_, char ** argv _U_)
1198 {
1199 struct arg dir = decode_arg("dir", factory->params, argc, argv);
1200 const char *sdir = ARG_STRING(dir);
1201 struct arg file = decode_arg("file", factory->params, argc, argv);
1202 const char *sfile = ARG_STRING(file);
1203
1204 int fd = inotify_init();
1205 if (fd < 0)
1206 err(EXIT_FAILURE, "failed in inotify_init()");
1207
1208 if (inotify_add_watch(fd, sdir, IN_DELETE) < 0) {
1209 int e = errno;
1210 close(fd);
1211 errno = e;
1212 err(EXIT_FAILURE, "failed in inotify_add_watch(\"%s\")", sdir);
1213 }
1214 free_arg(&dir);
1215
1216 if (inotify_add_watch(fd, sfile, IN_DELETE) < 0) {
1217 int e = errno;
1218 close(fd);
1219 errno = e;
1220 err(EXIT_FAILURE, "failed in inotify_add_watch(\"%s\")", sfile);
1221 }
1222 free_arg(&file);
1223
1224 if (fd != fdescs[0].fd) {
1225 if (dup2(fd, fdescs[0].fd) < 0) {
1226 int e = errno;
1227 close(fd);
1228 errno = e;
1229 err(EXIT_FAILURE, "failed to dup %d -> %d", fd, fdescs[0].fd);
1230 }
1231 close(fd);
1232 }
1233
1234 fdescs[0] = (struct fdesc){
1235 .fd = fdescs[0].fd,
1236 .close = close_fdesc,
1237 .data = NULL
1238 };
1239
1240 return NULL;
1241 }
1242
1243 static void close_unix_socket(int fd, void *data)
1244 {
1245 char *path = data;
1246 close(fd);
1247 if (path) {
1248 unlink(path);
1249 free(path);
1250 }
1251 }
1252
1253 static void *make_unix_stream_core(const struct factory *factory, struct fdesc fdescs[],
1254 int argc, char ** argv, int type, const char *typestr)
1255 {
1256 struct arg path = decode_arg("path", factory->params, argc, argv);
1257 const char *spath = ARG_STRING(path);
1258
1259 struct arg backlog = decode_arg("backlog", factory->params, argc, argv);
1260 int ibacklog = ARG_INTEGER(path);
1261
1262 struct arg abstract = decode_arg("abstract", factory->params, argc, argv);
1263 bool babstract = ARG_BOOLEAN(abstract);
1264
1265 struct arg server_shutdown = decode_arg("server-shutdown", factory->params, argc, argv);
1266 int iserver_shutdown = ARG_INTEGER(server_shutdown);
1267 struct arg client_shutdown = decode_arg("client-shutdown", factory->params, argc, argv);
1268 int iclient_shutdown = ARG_INTEGER(client_shutdown);
1269
1270 int ssd, csd, asd; /* server, client, and accepted socket descriptors */
1271 struct sockaddr_un un;
1272 size_t un_len = sizeof(un);
1273
1274 memset(&un, 0, sizeof(un));
1275 un.sun_family = AF_UNIX;
1276 if (babstract) {
1277 strncpy(un.sun_path + 1, spath, sizeof(un.sun_path) - 1 - 1);
1278 size_t pathlen = strlen(spath);
1279 if (sizeof(un.sun_path) - 1 > pathlen)
1280 un_len = sizeof(un) - sizeof(un.sun_path) + 1 + pathlen;
1281 } else
1282 strncpy(un.sun_path, spath, sizeof(un.sun_path) - 1 );
1283
1284 free_arg(&client_shutdown);
1285 free_arg(&server_shutdown);
1286 free_arg(&abstract);
1287 free_arg(&backlog);
1288 free_arg(&path);
1289
1290 if (iserver_shutdown < 0 || iserver_shutdown > 3)
1291 errx(EXIT_FAILURE, "the server shudown specification in unexpected range");
1292 if (iclient_shutdown < 0 || iclient_shutdown > 3)
1293 errx(EXIT_FAILURE, "the client shudown specification in unexpected range");
1294
1295 ssd = socket(AF_UNIX, type, 0);
1296 if (ssd < 0)
1297 err(EXIT_FAILURE,
1298 "failed to make a socket with AF_UNIX + SOCK_%s (server side)", typestr);
1299 if (ssd != fdescs[0].fd) {
1300 if (dup2(ssd, fdescs[0].fd) < 0) {
1301 int e = errno;
1302 close(ssd);
1303 errno = e;
1304 err(EXIT_FAILURE, "failed to dup %d -> %d", ssd, fdescs[0].fd);
1305 }
1306 close(ssd);
1307 ssd = fdescs[0].fd;
1308 }
1309
1310 fdescs[0] = (struct fdesc){
1311 .fd = fdescs[0].fd,
1312 .close = close_unix_socket,
1313 .data = NULL,
1314 };
1315
1316 if (!babstract)
1317 unlink(un.sun_path);
1318 if (bind(ssd, (const struct sockaddr *)&un, un_len) < 0) {
1319 int e = errno;
1320 close(ssd);
1321 errno = e;
1322 err(EXIT_FAILURE, "failed to bind a socket for listening");
1323 }
1324
1325 if (!babstract)
1326 fdescs[0].data = xstrdup(un.sun_path);
1327 if (listen(ssd, ibacklog) < 0) {
1328 int e = errno;
1329 close_unix_socket(ssd, fdescs[0].data);
1330 errno = e;
1331 err(EXIT_FAILURE, "failed to listen a socket");
1332 }
1333
1334 csd = socket(AF_UNIX, type, 0);
1335 if (csd < 0)
1336 err(EXIT_FAILURE,
1337 "failed to make a socket with AF_UNIX + SOCK_%s (client side)", typestr);
1338 if (csd != fdescs[1].fd) {
1339 if (dup2(csd, fdescs[1].fd) < 0) {
1340 int e = errno;
1341 close(csd);
1342 close_unix_socket(ssd, fdescs[0].data);
1343 errno = e;
1344 err(EXIT_FAILURE, "failed to dup %d -> %d", csd, fdescs[1].fd);
1345 }
1346 close(csd);
1347 csd = fdescs[1].fd;
1348 }
1349
1350 fdescs[1] = (struct fdesc){
1351 .fd = fdescs[1].fd,
1352 .close = close_fdesc,
1353 .data = NULL,
1354 };
1355
1356 if (connect(csd, (const struct sockaddr *)&un, un_len) < 0) {
1357 int e = errno;
1358 close_fdesc(csd, NULL);
1359 close_unix_socket(ssd, fdescs[0].data);
1360 errno = e;
1361 err(EXIT_FAILURE, "failed to connect a socket to the listening socket");
1362 }
1363
1364 if (!babstract)
1365 unlink(un.sun_path);
1366
1367 asd = accept(ssd, NULL, NULL);
1368 if (asd < 0) {
1369 int e = errno;
1370 close_fdesc(csd, NULL);
1371 close_unix_socket(ssd, fdescs[0].data);
1372 errno = e;
1373 err(EXIT_FAILURE, "failed to accept a socket from the listening socket");
1374 }
1375 if (asd != fdescs[2].fd) {
1376 if (dup2(asd, fdescs[2].fd) < 0) {
1377 int e = errno;
1378 close(asd);
1379 close_fdesc(csd, NULL);
1380 close_unix_socket(ssd, fdescs[0].data);
1381 errno = e;
1382 err(EXIT_FAILURE, "failed to dup %d -> %d", asd, fdescs[2].fd);
1383 }
1384 close(asd);
1385 asd = fdescs[2].fd;
1386 }
1387
1388 if (iserver_shutdown & (1 << 0))
1389 shutdown(asd, SHUT_RD);
1390 if (iserver_shutdown & (1 << 1))
1391 shutdown(asd, SHUT_WR);
1392 if (iclient_shutdown & (1 << 0))
1393 shutdown(csd, SHUT_RD);
1394 if (iclient_shutdown & (1 << 1))
1395 shutdown(csd, SHUT_WR);
1396
1397 return NULL;
1398 }
1399
1400 static void *make_unix_stream(const struct factory *factory, struct fdesc fdescs[],
1401 int argc, char ** argv)
1402 {
1403 struct arg type = decode_arg("type", factory->params, argc, argv);
1404 const char *stype = ARG_STRING(type);
1405
1406 int typesym;
1407 const char *typestr;
1408
1409 if (strcmp(stype, "stream") == 0) {
1410 typesym = SOCK_STREAM;
1411 typestr = "STREAM";
1412 } else if (strcmp(stype, "seqpacket") == 0) {
1413 typesym = SOCK_SEQPACKET;
1414 typestr = "SEQPACKET";
1415 } else
1416 errx(EXIT_FAILURE, "unknown unix socket type: %s", stype);
1417
1418 free_arg(&type);
1419
1420 return make_unix_stream_core(factory, fdescs, argc, argv, typesym, typestr);
1421 }
1422
1423 static void *make_unix_dgram(const struct factory *factory, struct fdesc fdescs[],
1424 int argc, char ** argv)
1425 {
1426 struct arg path = decode_arg("path", factory->params, argc, argv);
1427 const char *spath = ARG_STRING(path);
1428
1429 struct arg abstract = decode_arg("abstract", factory->params, argc, argv);
1430 bool babstract = ARG_BOOLEAN(abstract);
1431
1432 int ssd, csd; /* server and client socket descriptors */
1433
1434 struct sockaddr_un un;
1435 size_t un_len = sizeof(un);
1436
1437 memset(&un, 0, sizeof(un));
1438 un.sun_family = AF_UNIX;
1439 if (babstract) {
1440 strncpy(un.sun_path + 1, spath, sizeof(un.sun_path) - 1 - 1);
1441 size_t pathlen = strlen(spath);
1442 if (sizeof(un.sun_path) - 1 > pathlen)
1443 un_len = sizeof(un) - sizeof(un.sun_path) + 1 + pathlen;
1444 } else
1445 strncpy(un.sun_path, spath, sizeof(un.sun_path) - 1 );
1446
1447 free_arg(&abstract);
1448 free_arg(&path);
1449
1450 ssd = socket(AF_UNIX, SOCK_DGRAM, 0);
1451 if (ssd < 0)
1452 err(EXIT_FAILURE,
1453 "failed to make a socket with AF_UNIX + SOCK_DGRAM (server side)");
1454 if (ssd != fdescs[0].fd) {
1455 if (dup2(ssd, fdescs[0].fd) < 0) {
1456 int e = errno;
1457 close(ssd);
1458 errno = e;
1459 err(EXIT_FAILURE, "failed to dup %d -> %d", ssd, fdescs[0].fd);
1460 }
1461 close(ssd);
1462 ssd = fdescs[0].fd;
1463 }
1464
1465 fdescs[0] = (struct fdesc){
1466 .fd = fdescs[0].fd,
1467 .close = close_unix_socket,
1468 .data = NULL,
1469 };
1470
1471 if (!babstract)
1472 unlink(un.sun_path);
1473 if (bind(ssd, (const struct sockaddr *)&un, un_len) < 0) {
1474 int e = errno;
1475 close(ssd);
1476 errno = e;
1477 err(EXIT_FAILURE, "failed to bind a socket for server");
1478 }
1479
1480 if (!babstract)
1481 fdescs[0].data = xstrdup(un.sun_path);
1482 csd = socket(AF_UNIX, SOCK_DGRAM, 0);
1483 if (csd < 0)
1484 err(EXIT_FAILURE,
1485 "failed to make a socket with AF_UNIX + SOCK_DGRAM (client side)");
1486 if (csd != fdescs[1].fd) {
1487 if (dup2(csd, fdescs[1].fd) < 0) {
1488 int e = errno;
1489 close(csd);
1490 close_unix_socket(ssd, fdescs[0].data);
1491 errno = e;
1492 err(EXIT_FAILURE, "failed to dup %d -> %d", csd, fdescs[1].fd);
1493 }
1494 close(csd);
1495 csd = fdescs[1].fd;
1496 }
1497
1498 fdescs[1] = (struct fdesc){
1499 .fd = fdescs[1].fd,
1500 .close = close_fdesc,
1501 .data = NULL,
1502 };
1503
1504 if (connect(csd, (const struct sockaddr *)&un, un_len) < 0) {
1505 int e = errno;
1506 close_fdesc(csd, NULL);
1507 close_unix_socket(ssd, fdescs[0].data);
1508 errno = e;
1509 err(EXIT_FAILURE, "failed to connect a socket to the server socket");
1510 }
1511
1512 if (!babstract)
1513 unlink(un.sun_path);
1514
1515 return NULL;
1516 }
1517
1518 static void *make_unix_in_new_netns(const struct factory *factory, struct fdesc fdescs[],
1519 int argc, char ** argv)
1520 {
1521 struct arg type = decode_arg("type", factory->params, argc, argv);
1522 const char *stype = ARG_STRING(type);
1523
1524 struct arg path = decode_arg("path", factory->params, argc, argv);
1525 const char *spath = ARG_STRING(path);
1526
1527 struct arg abstract = decode_arg("abstract", factory->params, argc, argv);
1528 bool babstract = ARG_BOOLEAN(abstract);
1529
1530 int typesym;
1531 const char *typestr;
1532
1533 struct sockaddr_un un;
1534 size_t un_len = sizeof(un);
1535
1536 int self_netns, tmp_netns, sd;
1537
1538 if (strcmp(stype, "stream") == 0) {
1539 typesym = SOCK_STREAM;
1540 typestr = "STREAM";
1541 } else if (strcmp(stype, "seqpacket") == 0) {
1542 typesym = SOCK_SEQPACKET;
1543 typestr = "SEQPACKET";
1544 } else if (strcmp(stype, "dgram") == 0) {
1545 typesym = SOCK_DGRAM;
1546 typestr = "DGRAM";
1547 } else {
1548 free_arg(&abstract);
1549 free_arg(&path);
1550 free_arg(&type);
1551 errx(EXIT_FAILURE, "unknown unix socket type: %s", stype);
1552 }
1553
1554 memset(&un, 0, sizeof(un));
1555 un.sun_family = AF_UNIX;
1556 if (babstract) {
1557 strncpy(un.sun_path + 1, spath, sizeof(un.sun_path) - 1 - 1);
1558 size_t pathlen = strlen(spath);
1559 if (sizeof(un.sun_path) - 1 > pathlen)
1560 un_len = sizeof(un) - sizeof(un.sun_path) + 1 + pathlen;
1561 } else
1562 strncpy(un.sun_path, spath, sizeof(un.sun_path) - 1 );
1563
1564 free_arg(&abstract);
1565 free_arg(&path);
1566 free_arg(&type);
1567
1568 self_netns = open("/proc/self/ns/net", O_RDONLY);
1569 if (self_netns < 0)
1570 err(EXIT_FAILURE, "failed to open /proc/self/ns/net");
1571 if (self_netns != fdescs[0].fd) {
1572 if (dup2(self_netns, fdescs[0].fd) < 0) {
1573 int e = errno;
1574 close(self_netns);
1575 errno = e;
1576 err(EXIT_FAILURE, "failed to dup %d -> %d", self_netns, fdescs[0].fd);
1577 }
1578 close(self_netns);
1579 self_netns = fdescs[0].fd;
1580 }
1581
1582 fdescs[0] = (struct fdesc){
1583 .fd = fdescs[0].fd,
1584 .close = close_fdesc,
1585 .data = NULL,
1586 };
1587
1588 if (unshare(CLONE_NEWNET) < 0) {
1589 int e = errno;
1590 close_fdesc(self_netns, NULL);
1591 errno = e;
1592 err((errno == EPERM? EXIT_EPERM: EXIT_FAILURE),
1593 "failed in unshare");
1594 }
1595
1596 tmp_netns = open("/proc/self/ns/net", O_RDONLY);
1597 if (tmp_netns < 0) {
1598 int e = errno;
1599 close_fdesc(self_netns, NULL);
1600 errno = e;
1601 err(EXIT_FAILURE, "failed to open /proc/self/ns/net for the new netns");
1602 }
1603 if (tmp_netns != fdescs[1].fd) {
1604 if (dup2(tmp_netns, fdescs[1].fd) < 0) {
1605 int e = errno;
1606 close_fdesc(self_netns, NULL);
1607 close(tmp_netns);
1608 errno = e;
1609 err(EXIT_FAILURE, "failed to dup %d -> %d", tmp_netns, fdescs[1].fd);
1610 }
1611 close(tmp_netns);
1612 tmp_netns = fdescs[1].fd;
1613 }
1614
1615 fdescs[1] = (struct fdesc){
1616 .fd = fdescs[1].fd,
1617 .close = close_fdesc,
1618 .data = NULL,
1619 };
1620
1621 sd = socket(AF_UNIX, typesym, 0);
1622 if (sd < 0) {
1623 int e = errno;
1624 close_fdesc(self_netns, NULL);
1625 close_fdesc(tmp_netns, NULL);
1626 errno = e;
1627 err(EXIT_FAILURE,
1628 "failed to make a socket with AF_UNIX + SOCK_%s",
1629 typestr);
1630 }
1631
1632 if (sd != fdescs[2].fd) {
1633 if (dup2(sd, fdescs[2].fd) < 0) {
1634 int e = errno;
1635 close_fdesc(self_netns, NULL);
1636 close_fdesc(tmp_netns, NULL);
1637 close(sd);
1638 errno = e;
1639 err(EXIT_FAILURE, "failed to dup %d -> %d", sd, fdescs[2].fd);
1640 }
1641 close(sd);
1642 sd = fdescs[2].fd;
1643 }
1644
1645 fdescs[2] = (struct fdesc){
1646 .fd = fdescs[2].fd,
1647 .close = close_unix_socket,
1648 .data = NULL,
1649 };
1650
1651 if (!babstract)
1652 unlink(un.sun_path);
1653 if (bind(sd, (const struct sockaddr *)&un, un_len) < 0) {
1654 int e = errno;
1655 close_fdesc(self_netns, NULL);
1656 close_fdesc(tmp_netns, NULL);
1657 close_unix_socket(sd, NULL);
1658 errno = e;
1659 err(EXIT_FAILURE, "failed to bind a socket");
1660 }
1661
1662 if (!babstract)
1663 fdescs[2].data = xstrdup(un.sun_path);
1664
1665 if (typesym != SOCK_DGRAM) {
1666 if (listen(sd, 1) < 0) {
1667 int e = errno;
1668 close_fdesc(self_netns, NULL);
1669 close_fdesc(tmp_netns, NULL);
1670 close_unix_socket(sd, fdescs[2].data);
1671 errno = e;
1672 err(EXIT_FAILURE, "failed to listen a socket");
1673 }
1674 }
1675
1676 if (setns(self_netns, CLONE_NEWNET) < 0) {
1677 int e = errno;
1678 close_fdesc(self_netns, NULL);
1679 close_fdesc(tmp_netns, NULL);
1680 close_unix_socket(sd, fdescs[2].data);
1681 errno = e;
1682 err(EXIT_FAILURE, "failed to swich back to the original net namespace");
1683 }
1684
1685 return NULL;
1686 }
1687
1688 static void *make_tcp_common(const struct factory *factory, struct fdesc fdescs[],
1689 int argc, char ** argv,
1690 int family,
1691 void (*init_addr)(struct sockaddr *, unsigned short),
1692 size_t addr_size,
1693 struct sockaddr * sin, struct sockaddr * cin)
1694 {
1695 struct arg server_port = decode_arg("server-port", factory->params, argc, argv);
1696 unsigned short iserver_port = (unsigned short)ARG_INTEGER(server_port);
1697 struct arg client_port = decode_arg("client-port", factory->params, argc, argv);
1698 unsigned short iclient_port = (unsigned short)ARG_INTEGER(client_port);
1699
1700 int ssd, csd, asd;
1701
1702 const int y = 1;
1703
1704 free_arg(&server_port);
1705 free_arg(&client_port);
1706
1707 ssd = socket(family, SOCK_STREAM, 0);
1708 if (ssd < 0)
1709 err(EXIT_FAILURE,
1710 "failed to make a tcp socket for listening");
1711
1712 if (setsockopt(ssd, SOL_SOCKET,
1713 SO_REUSEADDR, (const char *)&y, sizeof(y)) < 0) {
1714 int e = errno;
1715 close(ssd);
1716 errno = e;
1717 err(EXIT_FAILURE, "failed to setsockopt(SO_REUSEADDR)");
1718 }
1719
1720 if (ssd != fdescs[0].fd) {
1721 if (dup2(ssd, fdescs[0].fd) < 0) {
1722 int e = errno;
1723 close(ssd);
1724 errno = e;
1725 err(EXIT_FAILURE, "failed to dup %d -> %d", ssd, fdescs[0].fd);
1726 }
1727 close(ssd);
1728 ssd = fdescs[0].fd;
1729 }
1730
1731 init_addr(sin, iserver_port);
1732 if (bind(ssd, sin, addr_size) < 0) {
1733 int e = errno;
1734 close(ssd);
1735 errno = e;
1736 err(EXIT_FAILURE, "failed to bind a listening socket");
1737 }
1738
1739 if (listen(ssd, 1) < 0) {
1740 int e = errno;
1741 close(ssd);
1742 errno = e;
1743 err(EXIT_FAILURE, "failed to listen a socket");
1744 }
1745
1746 csd = socket(family, SOCK_STREAM, 0);
1747 if (csd < 0) {
1748 int e = errno;
1749 close(ssd);
1750 errno = e;
1751 err(EXIT_FAILURE,
1752 "failed to make a tcp client socket");
1753 }
1754
1755 if (setsockopt(csd, SOL_SOCKET,
1756 SO_REUSEADDR, (const char *)&y, sizeof(y)) < 0) {
1757 int e = errno;
1758 close(ssd);
1759 close(csd);
1760 errno = e;
1761 err(EXIT_FAILURE, "failed to setsockopt(SO_REUSEADDR)");
1762 }
1763
1764 if (csd != fdescs[1].fd) {
1765 if (dup2(csd, fdescs[1].fd) < 0) {
1766 int e = errno;
1767 close(ssd);
1768 close(csd);
1769 errno = e;
1770 err(EXIT_FAILURE, "failed to dup %d -> %d", csd, fdescs[1].fd);
1771 }
1772 close(csd);
1773 csd = fdescs[1].fd;
1774 }
1775
1776 init_addr(cin, iclient_port);
1777 if (bind(csd, cin, addr_size) < 0) {
1778 int e = errno;
1779 close(ssd);
1780 close(csd);
1781 errno = e;
1782 err(EXIT_FAILURE, "failed to bind a client socket");
1783 }
1784
1785 if (connect(csd, sin, addr_size) < 0) {
1786 int e = errno;
1787 close(ssd);
1788 close(csd);
1789 errno = e;
1790 err(EXIT_FAILURE, "failed to connect a client socket to the server socket");
1791 }
1792
1793 asd = accept(ssd, NULL, NULL);
1794 if (asd < 0) {
1795 int e = errno;
1796 close(ssd);
1797 close(csd);
1798 errno = e;
1799 err(EXIT_FAILURE, "failed to accept a socket from the listening socket");
1800 }
1801 if (asd != fdescs[2].fd) {
1802 if (dup2(asd, fdescs[2].fd) < 0) {
1803 int e = errno;
1804 close(ssd);
1805 close(csd);
1806 errno = e;
1807 err(EXIT_FAILURE, "failed to dup %d -> %d", asd, fdescs[2].fd);
1808 }
1809 close(asd);
1810 asd = fdescs[2].fd;
1811 }
1812
1813 fdescs[0] = (struct fdesc) {
1814 .fd = fdescs[0].fd,
1815 .close = close_fdesc,
1816 .data = NULL,
1817 };
1818 fdescs[1] = (struct fdesc) {
1819 .fd = fdescs[1].fd,
1820 .close = close_fdesc,
1821 .data = NULL,
1822 };
1823 fdescs[2] = (struct fdesc) {
1824 .fd = fdescs[2].fd,
1825 .close = close_fdesc,
1826 .data = NULL,
1827 };
1828
1829 return NULL;
1830 }
1831
1832 static void tcp_init_addr(struct sockaddr *addr, unsigned short port)
1833 {
1834 struct sockaddr_in *in = (struct sockaddr_in *)addr;
1835 memset(in, 0, sizeof(*in));
1836 in->sin_family = AF_INET;
1837 in->sin_port = htons(port);
1838 in->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1839 }
1840
1841 static void *make_tcp(const struct factory *factory, struct fdesc fdescs[],
1842 int argc, char ** argv)
1843 {
1844 struct sockaddr_in sin, cin;
1845 return make_tcp_common(factory, fdescs, argc, argv,
1846 AF_INET,
1847 tcp_init_addr, sizeof(sin),
1848 (struct sockaddr *)&sin, (struct sockaddr *)&cin);
1849 }
1850
1851 static void *make_udp_common(const struct factory *factory, struct fdesc fdescs[],
1852 int argc, char ** argv,
1853 int family,
1854 void (*init_addr)(struct sockaddr *, unsigned short),
1855 size_t addr_size,
1856 struct sockaddr * sin, struct sockaddr * cin)
1857 {
1858 struct arg lite = decode_arg("lite", factory->params, argc, argv);
1859 bool blite = ARG_BOOLEAN(lite);
1860
1861 struct arg server_port = decode_arg("server-port", factory->params, argc, argv);
1862 unsigned short iserver_port = (unsigned short)ARG_INTEGER(server_port);
1863 struct arg client_port = decode_arg("client-port", factory->params, argc, argv);
1864 unsigned short iclient_port = (unsigned short)ARG_INTEGER(client_port);
1865
1866 struct arg server_do_bind = decode_arg("server-do-bind", factory->params, argc, argv);
1867 bool bserver_do_bind = ARG_BOOLEAN(server_do_bind);
1868 struct arg client_do_bind = decode_arg("client-do-bind", factory->params, argc, argv);
1869 bool bclient_do_bind = ARG_BOOLEAN(client_do_bind);
1870 struct arg client_do_connect = decode_arg("client-do-connect", factory->params, argc, argv);
1871 bool bclient_do_connect = ARG_BOOLEAN(client_do_connect);
1872
1873 int ssd, csd;
1874
1875 const int y = 1;
1876
1877 free_arg(&client_do_connect);
1878 free_arg(&client_do_bind);
1879 free_arg(&server_do_bind);
1880 free_arg(&server_port);
1881 free_arg(&client_port);
1882 free_arg(&lite);
1883
1884 ssd = socket(family, SOCK_DGRAM, blite? IPPROTO_UDPLITE: 0);
1885 if (ssd < 0)
1886 err(EXIT_FAILURE,
1887 "failed to make a udp socket for server");
1888
1889 if (setsockopt(ssd, SOL_SOCKET,
1890 SO_REUSEADDR, (const char *)&y, sizeof(y)) < 0) {
1891 int e = errno;
1892 close(ssd);
1893 errno = e;
1894 err(EXIT_FAILURE, "failed to setsockopt(SO_REUSEADDR)");
1895 }
1896
1897 if (ssd != fdescs[0].fd) {
1898 if (dup2(ssd, fdescs[0].fd) < 0) {
1899 int e = errno;
1900 close(ssd);
1901 errno = e;
1902 err(EXIT_FAILURE, "failed to dup %d -> %d", ssd, fdescs[0].fd);
1903 }
1904 close(ssd);
1905 ssd = fdescs[0].fd;
1906 }
1907
1908 init_addr(sin, iserver_port);
1909 if (bserver_do_bind) {
1910 if (bind(ssd, sin, addr_size) < 0) {
1911 int e = errno;
1912 close(ssd);
1913 errno = e;
1914 err(EXIT_FAILURE, "failed to bind a server socket");
1915 }
1916 }
1917
1918 csd = socket(family, SOCK_DGRAM, blite? IPPROTO_UDPLITE: 0);
1919 if (csd < 0) {
1920 int e = errno;
1921 close(ssd);
1922 errno = e;
1923 err(EXIT_FAILURE,
1924 "failed to make a udp client socket");
1925 }
1926
1927 if (setsockopt(csd, SOL_SOCKET,
1928 SO_REUSEADDR, (const char *)&y, sizeof(y)) < 0) {
1929 int e = errno;
1930 close(ssd);
1931 close(csd);
1932 errno = e;
1933 err(EXIT_FAILURE, "failed to setsockopt(SO_REUSEADDR)");
1934 }
1935
1936 if (csd != fdescs[1].fd) {
1937 if (dup2(csd, fdescs[1].fd) < 0) {
1938 int e = errno;
1939 close(ssd);
1940 close(csd);
1941 errno = e;
1942 err(EXIT_FAILURE, "failed to dup %d -> %d", csd, fdescs[1].fd);
1943 }
1944 close(csd);
1945 csd = fdescs[1].fd;
1946 }
1947
1948 if (bclient_do_bind) {
1949 init_addr(cin, iclient_port);
1950 if (bind(csd, cin, addr_size) < 0) {
1951 int e = errno;
1952 close(ssd);
1953 close(csd);
1954 errno = e;
1955 err(EXIT_FAILURE, "failed to bind a client socket");
1956 }
1957 }
1958
1959 if (bclient_do_connect) {
1960 if (connect(csd, sin, addr_size) < 0) {
1961 int e = errno;
1962 close(ssd);
1963 close(csd);
1964 errno = e;
1965 err(EXIT_FAILURE, "failed to connect a client socket to the server socket");
1966 }
1967 }
1968
1969 fdescs[0] = (struct fdesc) {
1970 .fd = fdescs[0].fd,
1971 .close = close_fdesc,
1972 .data = NULL,
1973 };
1974 fdescs[1] = (struct fdesc) {
1975 .fd = fdescs[1].fd,
1976 .close = close_fdesc,
1977 .data = NULL,
1978 };
1979
1980 return NULL;
1981 }
1982
1983 static void *make_udp(const struct factory *factory, struct fdesc fdescs[],
1984 int argc, char ** argv)
1985 {
1986 struct sockaddr_in sin, cin;
1987 return make_udp_common(factory, fdescs, argc, argv,
1988 AF_INET,
1989 tcp_init_addr, sizeof(sin),
1990 (struct sockaddr *)&sin, (struct sockaddr *)&cin);
1991 }
1992
1993 static void *make_raw_common(const struct factory *factory, struct fdesc fdescs[],
1994 int argc, char ** argv,
1995 int family,
1996 void (*init_addr)(struct sockaddr *, bool),
1997 size_t addr_size,
1998 struct sockaddr * sin)
1999 {
2000 struct arg protocol = decode_arg("protocol", factory->params, argc, argv);
2001 int iprotocol = ARG_INTEGER(protocol);
2002 int ssd;
2003
2004 free_arg(&protocol);
2005
2006 ssd = socket(family, SOCK_RAW, iprotocol);
2007 if (ssd < 0)
2008 err(EXIT_FAILURE,
2009 "failed to make a udp socket for server");
2010
2011 if (ssd != fdescs[0].fd) {
2012 if (dup2(ssd, fdescs[0].fd) < 0) {
2013 int e = errno;
2014 close(ssd);
2015 errno = e;
2016 err(EXIT_FAILURE, "failed to dup %d -> %d", ssd, fdescs[0].fd);
2017 }
2018 close(ssd);
2019 ssd = fdescs[0].fd;
2020 }
2021
2022 init_addr(sin, false);
2023 if (bind(ssd, sin, addr_size) < 0) {
2024 int e = errno;
2025 close(ssd);
2026 errno = e;
2027 err(EXIT_FAILURE, "failed in bind(2)");
2028 }
2029
2030 init_addr(sin, true);
2031 if (connect(ssd, sin, addr_size) < 0) {
2032 int e = errno;
2033 close(ssd);
2034 errno = e;
2035 err(EXIT_FAILURE, "failed in connect(2)");
2036 }
2037
2038 fdescs[0] = (struct fdesc) {
2039 .fd = fdescs[0].fd,
2040 .close = close_fdesc,
2041 .data = NULL,
2042 };
2043
2044 return NULL;
2045 }
2046
2047 static void raw_init_addr(struct sockaddr * addr, bool remote_addr)
2048 {
2049 struct sockaddr_in *in = (struct sockaddr_in *)addr;
2050 memset(in, 0, sizeof(*in));
2051 in->sin_family = AF_INET;
2052 in->sin_addr.s_addr = htonl(INADDR_LOOPBACK + (remote_addr? 1: 0));
2053 }
2054
2055 static void *make_raw(const struct factory *factory, struct fdesc fdescs[],
2056 int argc, char ** argv)
2057 {
2058 struct sockaddr_in sin;
2059 return make_raw_common(factory, fdescs, argc, argv,
2060 AF_INET,
2061 raw_init_addr, sizeof(sin),
2062 (struct sockaddr *)&sin);
2063 }
2064
2065 static void *make_ping_common(const struct factory *factory, struct fdesc fdescs[],
2066 int argc, char ** argv,
2067 int family, int protocol,
2068 void (*init_addr)(struct sockaddr *, unsigned short),
2069 size_t addr_size,
2070 struct sockaddr *sin)
2071 {
2072 struct arg connect_ = decode_arg("connect", factory->params, argc, argv);
2073 bool bconnect = ARG_BOOLEAN(connect_);
2074
2075 struct arg bind_ = decode_arg("bind", factory->params, argc, argv);
2076 bool bbind = ARG_BOOLEAN(bind_);
2077
2078 struct arg id = decode_arg("id", factory->params, argc, argv);
2079 unsigned short iid = (unsigned short)ARG_INTEGER(id);
2080
2081 int sd;
2082
2083 free_arg(&id);
2084 free_arg(&bind_);
2085 free_arg(&connect_);
2086
2087 sd = socket(family, SOCK_DGRAM, protocol);
2088 if (sd < 0)
2089 err((errno == EACCES? EXIT_EACCESS: EXIT_FAILURE),
2090 "failed to make an icmp socket");
2091
2092 if (sd != fdescs[0].fd) {
2093 if (dup2(sd, fdescs[0].fd) < 0) {
2094 int e = errno;
2095 close(sd);
2096 errno = e;
2097 err(EXIT_FAILURE, "failed to dup %d -> %d", sd, fdescs[0].fd);
2098 }
2099 close(sd);
2100 sd = fdescs[0].fd;
2101 }
2102
2103 if (bbind) {
2104 init_addr(sin, iid);
2105 if (bind(sd, sin, addr_size) < 0) {
2106 int e = errno;
2107 close(sd);
2108 errno = e;
2109 err((errno == EACCES? EXIT_EACCESS: EXIT_FAILURE),
2110 "failed in bind(2)");
2111 }
2112 }
2113
2114 if (bconnect) {
2115 init_addr(sin, 0);
2116 if (connect(sd, sin, addr_size) < 0) {
2117 int e = errno;
2118 close(sd);
2119 errno = e;
2120 err(EXIT_FAILURE, "failed in connect(2)");
2121 }
2122 }
2123
2124 fdescs[0] = (struct fdesc) {
2125 .fd = fdescs[0].fd,
2126 .close = close_fdesc,
2127 .data = NULL,
2128 };
2129
2130 return NULL;
2131 }
2132
2133 static void ping_init_addr(struct sockaddr *addr, unsigned short id)
2134 {
2135 struct sockaddr_in *in = (struct sockaddr_in *)addr;
2136 memset(in, 0, sizeof(*in));
2137 in->sin_family = AF_INET;
2138 in->sin_port = htons(id);
2139 in->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
2140 }
2141
2142 static void *make_ping(const struct factory *factory, struct fdesc fdescs[],
2143 int argc, char ** argv)
2144 {
2145 struct sockaddr_in in;
2146 return make_ping_common(factory, fdescs, argc, argv,
2147 AF_INET, IPPROTO_ICMP,
2148 ping_init_addr,
2149 sizeof(in),
2150 (struct sockaddr *)&in);
2151 }
2152
2153 static void tcp6_init_addr(struct sockaddr *addr, unsigned short port)
2154 {
2155 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr;
2156 memset(in6, 0, sizeof(*in6));
2157 in6->sin6_family = AF_INET6;
2158 in6->sin6_flowinfo = 0;
2159 in6->sin6_port = htons(port);
2160 in6->sin6_addr = in6addr_loopback;
2161 }
2162
2163 static void *make_tcp6(const struct factory *factory, struct fdesc fdescs[],
2164 int argc, char ** argv)
2165 {
2166 struct sockaddr_in6 sin, cin;
2167 return make_tcp_common(factory, fdescs, argc, argv,
2168 AF_INET6,
2169 tcp6_init_addr, sizeof(sin),
2170 (struct sockaddr *)&sin, (struct sockaddr *)&cin);
2171 }
2172
2173 static void *make_udp6(const struct factory *factory, struct fdesc fdescs[],
2174 int argc, char ** argv)
2175 {
2176 struct sockaddr_in6 sin, cin;
2177 return make_udp_common(factory, fdescs, argc, argv,
2178 AF_INET6,
2179 tcp6_init_addr, sizeof(sin),
2180 (struct sockaddr *)&sin, (struct sockaddr *)&cin);
2181 }
2182
2183 static void raw6_init_addr(struct sockaddr *addr, bool remote_addr)
2184 {
2185 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr;
2186 memset(in6, 0, sizeof(*in6));
2187 in6->sin6_family = AF_INET6;
2188 in6->sin6_flowinfo = 0;
2189
2190 if (remote_addr) {
2191 /* ::ffff:127.0.0.1 */
2192 in6->sin6_addr.s6_addr16[5] = 0xffff;
2193 in6->sin6_addr.s6_addr32[3] = htonl(INADDR_LOOPBACK);
2194 } else
2195 in6->sin6_addr = in6addr_loopback;
2196 }
2197
2198 static void *make_raw6(const struct factory *factory, struct fdesc fdescs[],
2199 int argc, char ** argv)
2200 {
2201 struct sockaddr_in6 sin;
2202 return make_raw_common(factory, fdescs, argc, argv,
2203 AF_INET6,
2204 raw6_init_addr, sizeof(sin),
2205 (struct sockaddr *)&sin);
2206 }
2207
2208 static void ping6_init_addr(struct sockaddr *addr, unsigned short id)
2209 {
2210 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr;
2211 memset(in6, 0, sizeof(*in6));
2212 in6->sin6_family = AF_INET6;
2213 in6->sin6_port = htons(id);
2214 in6->sin6_addr = in6addr_loopback;
2215 }
2216
2217 static void *make_ping6(const struct factory *factory, struct fdesc fdescs[],
2218 int argc, char ** argv)
2219 {
2220 struct sockaddr_in6 in6;
2221 return make_ping_common(factory, fdescs, argc, argv,
2222 AF_INET6, IPPROTO_ICMPV6,
2223 ping6_init_addr,
2224 sizeof(in6),
2225 (struct sockaddr *)&in6);
2226 }
2227
2228 static void *make_netns(const struct factory *factory _U_, struct fdesc fdescs[],
2229 int argc _U_, char ** argv _U_)
2230 {
2231 int sd = socket(AF_UNIX, SOCK_STREAM, 0);
2232 if (sd < 0)
2233 err(EXIT_FAILURE, "failed in socket()");
2234
2235 int ns = ioctl(sd, SIOCGSKNS);
2236 if (ns < 0)
2237 err_nosys(EXIT_FAILURE, "failed in ioctl(SIOCGSKNS)");
2238 close(sd);
2239
2240 if (ns != fdescs[0].fd) {
2241 if (dup2(ns, fdescs[0].fd) < 0) {
2242 int e = errno;
2243 close(ns);
2244 errno = e;
2245 err(EXIT_FAILURE, "failed to dup %d -> %d", ns, fdescs[0].fd);
2246 }
2247 close(ns);
2248 }
2249
2250 fdescs[0] = (struct fdesc){
2251 .fd = fdescs[0].fd,
2252 .close = close_fdesc,
2253 .data = NULL
2254 };
2255
2256 return NULL;
2257 }
2258
2259 static void *make_netlink(const struct factory *factory, struct fdesc fdescs[],
2260 int argc, char ** argv)
2261 {
2262 struct arg protocol = decode_arg("protocol", factory->params, argc, argv);
2263 int iprotocol = ARG_INTEGER(protocol);
2264 struct arg groups = decode_arg("groups", factory->params, argc, argv);
2265 unsigned int ugroups = ARG_UINTEGER(groups);
2266 int sd;
2267
2268 free_arg(&protocol);
2269
2270 sd = socket(AF_NETLINK, SOCK_RAW, iprotocol);
2271 if (sd < 0)
2272 err((errno == EPROTONOSUPPORT)? EXIT_EPROTONOSUPPORT: EXIT_FAILURE,
2273 "failed in socket()");
2274
2275 if (sd != fdescs[0].fd) {
2276 if (dup2(sd, fdescs[0].fd) < 0) {
2277 int e = errno;
2278 close(sd);
2279 errno = e;
2280 err(EXIT_FAILURE, "failed to dup %d -> %d", sd, fdescs[0].fd);
2281 }
2282 close(sd);
2283 }
2284
2285 struct sockaddr_nl nl;
2286 memset(&nl, 0, sizeof(nl));
2287 nl.nl_family = AF_NETLINK;
2288 nl.nl_groups = ugroups;
2289 if (bind(sd, (struct sockaddr*)&nl, sizeof(nl)) < 0) {
2290 int e = errno;
2291 close(sd);
2292 errno = e;
2293 err(EXIT_FAILURE, "failed in bind(2)");
2294 }
2295
2296 fdescs[0] = (struct fdesc){
2297 .fd = fdescs[0].fd,
2298 .close = close_fdesc,
2299 .data = NULL
2300 };
2301
2302 return NULL;
2303 }
2304
2305 static void *make_eventfd(const struct factory *factory _U_, struct fdesc fdescs[],
2306 int argc _U_, char ** argv _U_)
2307 {
2308 int fd;
2309 pid_t *pid = xcalloc(1, sizeof(*pid));
2310
2311 if (fdescs[0].fd == fdescs[1].fd)
2312 errx(EXIT_FAILURE, "specify three different numbers as file descriptors");
2313
2314 fd = eventfd(0, 0);
2315 if (fd < 0)
2316 err(EXIT_FAILURE, "failed in eventfd(2)");
2317
2318 if (fd != fdescs[0].fd) {
2319 if (dup2(fd, fdescs[0].fd) < 0) {
2320 int e = errno;
2321 close(fd);
2322 errno = e;
2323 err(EXIT_FAILURE, "failed to dup %d -> %d", fd, fdescs[0].fd);
2324 }
2325 close(fd);
2326 }
2327
2328 fdescs[0] = (struct fdesc){
2329 .fd = fdescs[0].fd,
2330 .close = close_fdesc,
2331 .data = NULL
2332 };
2333
2334 if (dup2(fdescs[0].fd, fdescs[1].fd) < 0) {
2335 int e = errno;
2336 close(fdescs[0].fd);
2337 errno = e;
2338 err(EXIT_FAILURE, "failed to dup %d -> %d", fdescs[0].fd, fdescs[1].fd);
2339 }
2340
2341 signal(SIGCHLD, abort_with_child_death_message);
2342 *pid = fork();
2343 if (*pid < -1) {
2344 int e = errno;
2345 close(fdescs[0].fd);
2346 close(fdescs[1].fd);
2347 errno = e;
2348 err(EXIT_FAILURE, "failed in fork()");
2349 } else if (*pid == 0) {
2350 uint64_t v = 1;
2351
2352 free(pid);
2353 close(fdescs[0].fd);
2354
2355 signal(SIGCONT, do_nothing);
2356 /* Notify the parent that I'm ready. */
2357 if (write(fdescs[1].fd, &v, sizeof(v)) != sizeof(v)) {
2358 close(fdescs[1].fd);
2359 err(EXIT_FAILURE,
2360 "failed in write() to notify the readiness to the prent");
2361 }
2362 /* Wait till the parent lets me go. */
2363 pause();
2364
2365 close(fdescs[1].fd);
2366 exit(0);
2367 } else {
2368 uint64_t v;
2369
2370 /* The child owns fdescs[1]. */
2371 close(fdescs[1].fd);
2372 fdescs[1].fd = -1;
2373
2374 /* Wait till the child is ready. */
2375 if (read(fdescs[0].fd, &v, sizeof(uint64_t)) != sizeof(v)) {
2376 free(pid);
2377 close(fdescs[0].fd);
2378 err(EXIT_FAILURE,
2379 "failed in read() the readiness notification from the child");
2380 }
2381 signal(SIGCHLD, SIG_DFL);
2382 }
2383
2384 return pid;
2385 }
2386
2387 static void report_eventfd(const struct factory *factory _U_,
2388 int nth, void *data, FILE *fp)
2389 {
2390 if (nth == 0) {
2391 pid_t *child = data;
2392 fprintf(fp, "%d", *child);
2393 }
2394 }
2395
2396 static void free_eventfd(const struct factory * factory _U_, void *data)
2397 {
2398 pid_t child = *(pid_t *)data;
2399 int wstatus;
2400
2401 free(data);
2402
2403 kill(child, SIGCONT);
2404 if (waitpid(child, &wstatus, 0) < 0)
2405 err(EXIT_FAILURE, "failed in waitpid()");
2406
2407 if (WIFEXITED(wstatus)) {
2408 int s = WEXITSTATUS(wstatus);
2409 if (s != 0)
2410 err(EXIT_FAILURE, "the child process got an error: %d", s);
2411 } else if (WIFSIGNALED(wstatus)) {
2412 int s = WTERMSIG(wstatus);
2413 if (WTERMSIG(wstatus) != 0)
2414 err(EXIT_FAILURE, "the child process got a signal: %d", s);
2415 }
2416 }
2417
2418 struct mqueue_data {
2419 pid_t pid;
2420 const char *path;
2421 bool created;
2422 };
2423
2424 static void mqueue_data_free(struct mqueue_data *data)
2425 {
2426 if (data->created)
2427 mq_unlink(data->path);
2428 free((void *)data->path);
2429 free(data);
2430 }
2431
2432 static void report_mqueue(const struct factory *factory _U_,
2433 int nth, void *data, FILE *fp)
2434 {
2435 if (nth == 0) {
2436 fprintf(fp, "%d", ((struct mqueue_data *)data)->pid);
2437 }
2438 }
2439
2440 static void close_mqueue(int fd, void *data _U_)
2441 {
2442 mq_close(fd);
2443 }
2444
2445 static void free_mqueue(const struct factory * factory _U_, void *data)
2446 {
2447 struct mqueue_data *mqueue_data = data;
2448 pid_t child = mqueue_data->pid;
2449 int wstatus;
2450
2451 mqueue_data_free(mqueue_data);
2452
2453 kill(child, SIGCONT);
2454 if (waitpid(child, &wstatus, 0) < 0)
2455 err(EXIT_FAILURE, "failed in waitpid()");
2456
2457 if (WIFEXITED(wstatus)) {
2458 int s = WEXITSTATUS(wstatus);
2459 if (s != 0)
2460 err(EXIT_FAILURE, "the child process got an error: %d", s);
2461 } else if (WIFSIGNALED(wstatus)) {
2462 int s = WTERMSIG(wstatus);
2463 if (WTERMSIG(wstatus) != 0)
2464 err(EXIT_FAILURE, "the child process got a signal: %d", s);
2465 }
2466 }
2467
2468 static void *make_mqueue(const struct factory *factory, struct fdesc fdescs[],
2469 int argc, char ** argv)
2470 {
2471 struct mqueue_data *mqueue_data;
2472 struct arg path = decode_arg("path", factory->params, argc, argv);
2473 const char *spath = ARG_STRING(path);
2474
2475 struct mq_attr attr = {
2476 .mq_maxmsg = 1,
2477 .mq_msgsize = 1,
2478 };
2479
2480 int fd;
2481
2482 if (spath[0] != '/')
2483 errx(EXIT_FAILURE, "the path for mqueue must start with '/': %s", spath);
2484
2485 if (spath[0] == '\0')
2486 err(EXIT_FAILURE, "the path should not be empty");
2487
2488 if (fdescs[0].fd == fdescs[1].fd)
2489 errx(EXIT_FAILURE, "specify three different numbers as file descriptors");
2490
2491 mqueue_data = xmalloc(sizeof(*mqueue_data));
2492 mqueue_data->pid = 0;
2493 mqueue_data->path = xstrdup(spath);
2494 mqueue_data->created = false;
2495
2496 free_arg(&path);
2497
2498 fd = mq_open(mqueue_data->path, O_CREAT|O_EXCL | O_RDONLY, S_IRUSR | S_IWUSR, &attr);
2499 if (fd < 0) {
2500 mqueue_data_free(mqueue_data);
2501 err(EXIT_FAILURE, "failed in mq_open(3) for reading");
2502 }
2503
2504 mqueue_data->created = true;
2505 if (fd != fdescs[0].fd) {
2506 if (dup2(fd, fdescs[0].fd) < 0) {
2507 int e = errno;
2508 mq_close(fd);
2509 mqueue_data_free(mqueue_data);
2510 errno = e;
2511 err(EXIT_FAILURE, "failed to dup %d -> %d", fd, fdescs[0].fd);
2512 }
2513 mq_close(fd);
2514 }
2515
2516 fdescs[0] = (struct fdesc){
2517 .fd = fdescs[0].fd,
2518 .close = close_mqueue,
2519 .data = NULL
2520 };
2521
2522 fd = mq_open(mqueue_data->path, O_WRONLY, S_IRUSR | S_IWUSR, NULL);
2523 if (fd < 0) {
2524 int e = errno;
2525 mq_close(fdescs[0].fd);
2526 mqueue_data_free(mqueue_data);
2527 errno = e;
2528 err(EXIT_FAILURE, "failed in mq_open(3) for writing");
2529 }
2530
2531 if (fd != fdescs[1].fd) {
2532 if (dup2(fd, fdescs[1].fd) < 0) {
2533 int e = errno;
2534 mq_close(fd);
2535 mq_close(fdescs[0].fd);
2536 errno = e;
2537 err(EXIT_FAILURE, "failed to dup %d -> %d", fd, fdescs[1].fd);
2538 }
2539 mq_close(fd);
2540 }
2541 fdescs[1] = (struct fdesc){
2542 .fd = fdescs[1].fd,
2543 .close = close_mqueue,
2544 .data = NULL
2545 };
2546
2547 signal(SIGCHLD, abort_with_child_death_message);
2548 mqueue_data->pid = fork();
2549 if (mqueue_data->pid < -1) {
2550 int e = errno;
2551 mq_close(fdescs[0].fd);
2552 mq_close(fdescs[1].fd);
2553 mqueue_data_free(mqueue_data);
2554 errno = e;
2555 err(EXIT_FAILURE, "failed in fork()");
2556 } else if (mqueue_data->pid == 0) {
2557 mqueue_data->created = false;
2558 mqueue_data_free(mqueue_data);
2559 mq_close(fdescs[0].fd);
2560
2561 signal(SIGCONT, do_nothing);
2562 /* Notify the parent that I'm ready. */
2563 if (mq_send(fdescs[1].fd, "", 0, 0) < 0)
2564 err(EXIT_FAILURE,
2565 "failed in mq_send() to notify the readiness to the prent");
2566 /* Wait till the parent lets me go. */
2567 pause();
2568
2569 mq_close(fdescs[1].fd);
2570 exit(0);
2571 } else {
2572 char c;
2573
2574 /* The child owns fdescs[1]. */
2575 mq_close(fdescs[1].fd);
2576 fdescs[1].fd = -1;
2577
2578 /* Wait till the child is ready. */
2579 if (mq_receive(fdescs[0].fd, &c, 1, NULL) < 0) {
2580 mq_close(fdescs[0].fd);
2581 mqueue_data_free(mqueue_data);
2582 err(EXIT_FAILURE,
2583 "failed in mq_receive() the readiness notification from the child");
2584 }
2585 signal(SIGCHLD, SIG_DFL);
2586 }
2587
2588 return mqueue_data;
2589 }
2590 struct sysvshm_data {
2591 void *addr;
2592 int id;
2593 };
2594
2595 static void *make_sysvshm(const struct factory *factory _U_, struct fdesc fdescs[] _U_,
2596 int argc _U_, char ** argv _U_)
2597 {
2598 size_t pagesize = getpagesize();
2599 struct sysvshm_data *sysvshm_data;
2600 int id = shmget(IPC_PRIVATE, pagesize, IPC_CREAT | 0600);
2601 void *start;
2602
2603 if (id == -1)
2604 err(EXIT_FAILURE, "failed to do shmget(.., %zu, ...)",
2605 pagesize);
2606
2607 start = shmat(id, NULL, SHM_RDONLY);
2608 if (start == (void *) -1) {
2609 int e = errno;
2610 shmctl(id, IPC_RMID, NULL);
2611 errno = e;
2612 err(EXIT_FAILURE, "failed to do shmat(%d,...)", id);
2613 }
2614
2615 sysvshm_data = xmalloc(sizeof(*sysvshm_data));
2616 sysvshm_data->addr = start;
2617 sysvshm_data->id = id;
2618 return sysvshm_data;
2619 }
2620
2621 static void free_sysvshm(const struct factory *factory _U_, void *data)
2622 {
2623 struct sysvshm_data *sysvshm_data = data;
2624
2625 shmdt(sysvshm_data->addr);
2626 shmctl(sysvshm_data->id, IPC_RMID, NULL);
2627 }
2628
2629 static void *make_eventpoll(const struct factory *factory _U_, struct fdesc fdescs[],
2630 int argc _U_, char ** argv _U_)
2631 {
2632 int efd;
2633 struct spec {
2634 const char *file;
2635 int flag;
2636 uint32_t events;
2637 } specs [] = {
2638 {
2639 .file = "DUMMY, DONT'USE THIS"
2640 }, {
2641 .file = "/dev/random",
2642 .flag = O_RDONLY,
2643 .events = EPOLLIN,
2644 }, {
2645 .file = "/dev/random",
2646 .flag = O_WRONLY,
2647 .events = EPOLLOUT,
2648 },
2649 };
2650
2651 efd = epoll_create(1);
2652 if (efd < 0)
2653 err(EXIT_FAILURE, "failed in epoll_create(2)");
2654 if (efd != fdescs[0].fd) {
2655 if (dup2(efd, fdescs[0].fd) < 0) {
2656 int e = errno;
2657 close(efd);
2658 errno = e;
2659 err(EXIT_FAILURE, "failed to dup %d -> %d", efd, fdescs[0].fd);
2660 }
2661 close(efd);
2662 efd = fdescs[0].fd;
2663 }
2664 fdescs[0] = (struct fdesc){
2665 .fd = fdescs[0].fd,
2666 .close = close_fdesc,
2667 .data = NULL
2668 };
2669
2670 for (size_t i = 1; i < ARRAY_SIZE(specs); i++) {
2671 int fd = open(specs[i].file, specs[i].flag);
2672 if (fd < 0) {
2673 int e = errno;
2674 close(efd);
2675 for (size_t j = i - 1; j > 0; j--)
2676 close(fdescs[j].fd);
2677 errno = e;
2678 err(EXIT_FAILURE, "failed in open(\"%s\",...)",
2679 specs[i].file);
2680 }
2681 if (fd != fdescs[i].fd) {
2682 if (dup2(fd, fdescs[i].fd) < 0) {
2683 int e = errno;
2684 close(efd);
2685 for (size_t j = i - 1; j > 0; j--)
2686 close(fdescs[j].fd);
2687 close(fd);
2688 errno = e;
2689 err(EXIT_FAILURE, "failed to dup %d -> %d",
2690 fd, fdescs[i].fd);
2691 }
2692 close(fd);
2693 }
2694 fdescs[i] = (struct fdesc) {
2695 .fd = fdescs[i].fd,
2696 .close = close_fdesc,
2697 .data = NULL
2698 };
2699 if (epoll_ctl(efd, EPOLL_CTL_ADD, fdescs[i].fd,
2700 &(struct epoll_event) {
2701 .events = specs[i].events,
2702 .data = {.ptr = NULL,}
2703 }) < 0) {
2704 int e = errno;
2705 close(efd);
2706 for (size_t j = i; j > 0; j--)
2707 close(fdescs[j].fd);
2708 errno = e;
2709 err (EXIT_FAILURE,
2710 "failed to add fd %d to the eventpoll fd with epoll_ctl",
2711 fdescs[i].fd);
2712 }
2713 }
2714
2715 return NULL;
2716 }
2717
2718 static bool decode_clockid(const char *sclockid, clockid_t *clockid)
2719 {
2720 if (sclockid == NULL)
2721 return false;
2722 if (sclockid[0] == '\0')
2723 return false;
2724
2725 if (strcmp(sclockid, "realtime") == 0)
2726 *clockid = CLOCK_REALTIME;
2727 else if (strcmp(sclockid, "monotonic") == 0)
2728 *clockid = CLOCK_MONOTONIC;
2729 else if (strcmp(sclockid, "boottime") == 0)
2730 *clockid = CLOCK_BOOTTIME;
2731 else if (strcmp(sclockid, "realtime-alarm") == 0)
2732 *clockid = CLOCK_REALTIME_ALARM;
2733 else if (strcmp(sclockid, "boottime-alarm") == 0)
2734 *clockid = CLOCK_BOOTTIME_ALARM;
2735 else
2736 return false;
2737 return true;
2738 }
2739
2740 static void *make_timerfd(const struct factory *factory, struct fdesc fdescs[],
2741 int argc, char ** argv)
2742 {
2743 int tfd;
2744 struct timespec now;
2745 struct itimerspec tspec;
2746
2747 struct arg abstime = decode_arg("abstime", factory->params, argc, argv);
2748 bool babstime = ARG_BOOLEAN(abstime);
2749
2750 struct arg remaining = decode_arg("remaining", factory->params, argc, argv);
2751 unsigned int uremaining = ARG_UINTEGER(remaining);
2752
2753 struct arg interval = decode_arg("interval", factory->params, argc, argv);
2754 unsigned int uinterval = ARG_UINTEGER(interval);
2755
2756 struct arg interval_frac = decode_arg("interval-nanofrac", factory->params, argc, argv);
2757 unsigned int uinterval_frac = ARG_UINTEGER(interval_frac);
2758
2759 struct arg clockid_ = decode_arg("clockid", factory->params, argc, argv);
2760 const char *sclockid = ARG_STRING(clockid_);
2761 clockid_t clockid;
2762
2763 if (decode_clockid (sclockid, &clockid) == false)
2764 err(EXIT_FAILURE, "unknown clockid: %s", sclockid);
2765
2766 free_arg(&clockid_);
2767 free_arg(&interval_frac);
2768 free_arg(&interval);
2769 free_arg(&remaining);
2770 free_arg(&abstime);
2771
2772 if (babstime) {
2773 int r = clock_gettime(clockid, &now);
2774 if (r == -1)
2775 err(EXIT_FAILURE, "failed in clock_gettime(2)");
2776 }
2777
2778 tfd = timerfd_create(clockid, 0);
2779 if (tfd < 0)
2780 err(EXIT_FAILURE, "failed in timerfd_create(2)");
2781
2782 tspec.it_value.tv_sec = (babstime? now.tv_sec: 0) + uremaining;
2783 tspec.it_value.tv_nsec = (babstime? now.tv_nsec: 0);
2784
2785 tspec.it_interval.tv_sec = uinterval;
2786 tspec.it_interval.tv_nsec = uinterval_frac;
2787
2788 if (timerfd_settime(tfd, babstime? TFD_TIMER_ABSTIME: 0, &tspec, NULL) < 0) {
2789 int e = errno;
2790 close(tfd);
2791 errno = e;
2792 err(EXIT_FAILURE, "failed in timerfd_settime(2)");
2793 }
2794
2795 if (tfd != fdescs[0].fd) {
2796 if (dup2(tfd, fdescs[0].fd) < 0) {
2797 int e = errno;
2798 close(tfd);
2799 errno = e;
2800 err(EXIT_FAILURE, "failed to dup %d -> %d", tfd, fdescs[0].fd);
2801 }
2802 close(tfd);
2803 }
2804
2805 fdescs[0] = (struct fdesc){
2806 .fd = fdescs[0].fd,
2807 .close = close_fdesc,
2808 .data = NULL
2809 };
2810
2811 return NULL;
2812 }
2813
2814 static void *make_signalfd(const struct factory *factory _U_, struct fdesc fdescs[],
2815 int argc _U_, char ** argv _U_)
2816 {
2817 sigset_t mask;
2818 int numsig = 42;
2819
2820 if (sigemptyset(&mask) < 0)
2821 err(EXIT_FAILURE, "failed in sigemptyset()");
2822 if (sigaddset(&mask, SIGFPE) < 0)
2823 err(EXIT_FAILURE, "failed in sigaddset(FPE)");
2824 if (sigaddset(&mask, SIGUSR1) < 0)
2825 err(EXIT_FAILURE, "failed in sigaddset(USR1)");
2826 if (sigaddset(&mask, numsig) < 0)
2827 err(EXIT_FAILURE, "failed in sigaddset(%d)", numsig);
2828
2829 int sfd= signalfd(-1, &mask, 0);
2830 if (sfd < 0)
2831 err(EXIT_FAILURE, "failed in signalfd(2)");
2832
2833 if (sfd != fdescs[0].fd) {
2834 if (dup2(sfd, fdescs[0].fd) < 0) {
2835 int e = errno;
2836 close(sfd);
2837 errno = e;
2838 err(EXIT_FAILURE, "failed to dup %d -> %d", sfd, fdescs[0].fd);
2839 }
2840 close(sfd);
2841 }
2842
2843 fdescs[0] = (struct fdesc){
2844 .fd = fdescs[0].fd,
2845 .close = close_fdesc,
2846 .data = NULL
2847 };
2848
2849 return NULL;
2850 }
2851
2852
2853 /* ref. linux/Documentation/networking/tuntap.rst */
2854 static void *make_cdev_tun(const struct factory *factory _U_, struct fdesc fdescs[],
2855 int argc _U_, char ** argv _U_)
2856 {
2857 int tfd = open("/dev/net/tun", O_RDWR);
2858 struct ifreq ifr;
2859
2860 if (tfd < 0)
2861 err(EXIT_FAILURE, "failed in opening /dev/net/tun");
2862
2863 memset(&ifr, 0, sizeof(ifr));
2864
2865 ifr.ifr_flags = IFF_TUN;
2866 strcpy(ifr.ifr_name, "mkfds%d");
2867
2868 if (ioctl(tfd, TUNSETIFF, (void *) &ifr) < 0) {
2869 int e = errno;
2870 close(tfd);
2871 errno = e;
2872 err(EXIT_FAILURE, "failed in setting \"lo\" to the tun device");
2873 }
2874
2875 if (tfd != fdescs[0].fd) {
2876 if (dup2(tfd, fdescs[0].fd) < 0) {
2877 int e = errno;
2878 close(tfd);
2879 errno = e;
2880 err(EXIT_FAILURE, "failed to dup %d -> %d", tfd, fdescs[0].fd);
2881 }
2882 close(tfd);
2883 }
2884
2885 fdescs[0] = (struct fdesc){
2886 .fd = fdescs[0].fd,
2887 .close = close_fdesc,
2888 .data = NULL
2889 };
2890
2891 return xstrdup(ifr.ifr_name);
2892 }
2893
2894 static void report_cdev_tun(const struct factory *factory _U_,
2895 int nth, void *data, FILE *fp)
2896 {
2897 if (nth == 0) {
2898 char *devname = data;
2899 fprintf(fp, "%s", devname);
2900 }
2901 }
2902
2903 static void free_cdev_tun(const struct factory * factory _U_, void *data)
2904 {
2905 free(data);
2906 }
2907
2908 static void *make_bpf_prog(const struct factory *factory, struct fdesc fdescs[],
2909 int argc, char ** argv)
2910 {
2911 struct arg prog_type_id = decode_arg("prog-type-id", factory->params, argc, argv);
2912 int iprog_type_id = ARG_INTEGER(prog_type_id);
2913
2914 struct arg name = decode_arg("name", factory->params, argc, argv);
2915 const char *sname = ARG_STRING(name);
2916
2917 int bfd;
2918 union bpf_attr attr;
2919 /* Just doing exit with 0. */
2920 struct bpf_insn insns[] = {
2921 [0] = {
2922 .code = BPF_ALU64 | BPF_MOV | BPF_K,
2923 .dst_reg = BPF_REG_0, .src_reg = 0, .off = 0, .imm = 0
2924 },
2925 [1] = {
2926 .code = BPF_JMP | BPF_EXIT,
2927 .dst_reg = 0, .src_reg = 0, .off = 0, .imm = 0
2928 },
2929 };
2930
2931 memset(&attr, 0, sizeof(attr));
2932 attr.prog_type = iprog_type_id;
2933 attr.insns = (uint64_t)(unsigned long)insns;
2934 attr.insn_cnt = ARRAY_SIZE(insns);
2935 attr.license = (int64_t)(unsigned long)"GPL";
2936 strncpy(attr.prog_name, sname, sizeof(attr.prog_name) - 1);
2937
2938 free_arg(&name);
2939 free_arg(&prog_type_id);
2940
2941 bfd = syscall(SYS_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
2942 if (bfd < 0)
2943 err_nosys(EXIT_FAILURE, "failed in bpf(BPF_PROG_LOAD)");
2944
2945 if (bfd != fdescs[0].fd) {
2946 if (dup2(bfd, fdescs[0].fd) < 0) {
2947 int e = errno;
2948 close(bfd);
2949 errno = e;
2950 err(EXIT_FAILURE, "failed to dup %d -> %d", bfd, fdescs[0].fd);
2951 }
2952 close(bfd);
2953 }
2954
2955 fdescs[0] = (struct fdesc){
2956 .fd = fdescs[0].fd,
2957 .close = close_fdesc,
2958 .data = NULL
2959 };
2960
2961 return NULL;
2962 }
2963
2964 static void *make_some_pipes(const struct factory *factory _U_, struct fdesc fdescs[],
2965 int argc _U_, char ** argv _U_)
2966 {
2967 /* Reserver fds before making pipes */
2968 for (int i = 0; i < factory->N; i++) {
2969 close(fdescs[i].fd);
2970 if (dup2(0, fdescs[0].fd) < 0)
2971 err(EXIT_FAILURE, "failed to reserve fd %d with dup2", fdescs[0].fd);
2972 }
2973
2974 for (int i = 0; i < (factory->N) / 2; i++) {
2975 int pd[2];
2976 unsigned int mode;
2977 int r = 0, w = 1;
2978
2979 mode = 1 << (i % 3);
2980 if (mode == MX_WRITE) {
2981 r = 1;
2982 w = 0;
2983 }
2984
2985 if (pipe(pd) < 0)
2986 err(EXIT_FAILURE, "failed to make pipe");
2987
2988 if (dup2(pd[0], fdescs[2 * i + r].fd) < 0)
2989 err(EXIT_FAILURE, "failed to dup %d -> %d", pd[0], fdescs[2 * i + r].fd);
2990 close(pd[0]);
2991 fdescs[2 * 1 + r].close = close_fdesc;
2992
2993 if (dup2(pd[1], fdescs[2 * i + w].fd) < 0)
2994 err(EXIT_FAILURE, "failed to dup %d -> %d", pd[1], fdescs[2 * i + 2].fd);
2995 close(pd[1]);
2996 fdescs[2 * 1 + w].close = close_fdesc;
2997
2998 fdescs[2 * i].mx_modes |= mode;
2999
3000 /* Make the pipe for writing full. */
3001 if (fdescs[2 * i].mx_modes & MX_WRITE) {
3002 int n = fcntl(fdescs[2 * i].fd, F_GETPIPE_SZ);
3003 char *buf;
3004
3005 if (n < 0)
3006 err(EXIT_FAILURE, "failed to get PIPE BUFFER SIZE from %d", fdescs[2 * i].fd);
3007
3008 buf = xmalloc(n);
3009 if (write(fdescs[2 * i].fd, buf, n) != n)
3010 err(EXIT_FAILURE, "failed to fill the pipe buffer specified with %d",
3011 fdescs[2 * i].fd);
3012 free(buf);
3013 }
3014
3015 }
3016
3017 return NULL;
3018 }
3019
3020 static void *make_bpf_map(const struct factory *factory, struct fdesc fdescs[],
3021 int argc, char ** argv)
3022 {
3023 struct arg map_type_id = decode_arg("map-type-id", factory->params, argc, argv);
3024 int imap_type_id = ARG_INTEGER(map_type_id);
3025
3026 struct arg name = decode_arg("name", factory->params, argc, argv);
3027 const char *sname = ARG_STRING(name);
3028
3029 int bfd;
3030 union bpf_attr attr = {
3031 .map_type = imap_type_id,
3032 .key_size = 4,
3033 .value_size = 4,
3034 .max_entries = 10,
3035 };
3036
3037 strncpy(attr.map_name, sname, sizeof(attr.map_name) - 1);
3038
3039 free_arg(&name);
3040 free_arg(&map_type_id);
3041
3042 bfd = syscall(SYS_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
3043 if (bfd < 0)
3044 err_nosys(EXIT_FAILURE, "failed in bpf(BPF_MAP_CREATE)");
3045
3046 if (bfd != fdescs[0].fd) {
3047 if (dup2(bfd, fdescs[0].fd) < 0) {
3048 int e = errno;
3049 close(bfd);
3050 errno = e;
3051 err(EXIT_FAILURE, "failed to dup %d -> %d", bfd, fdescs[0].fd);
3052 }
3053 close(bfd);
3054 }
3055
3056 fdescs[0] = (struct fdesc){
3057 .fd = fdescs[0].fd,
3058 .close = close_fdesc,
3059 .data = NULL
3060 };
3061
3062 return NULL;
3063 }
3064
3065 static void *make_pty(const struct factory *factory _U_, struct fdesc fdescs[],
3066 int argc _U_, char ** argv _U_)
3067 {
3068 int index, *indexp;
3069 char *pts;
3070 int pts_fd;
3071 int ptmx_fd = posix_openpt(O_RDWR);
3072 if (ptmx_fd < 0)
3073 err(EXIT_FAILURE, "failed in opening /dev/ptmx");
3074
3075 if (unlockpt(ptmx_fd) < 0) {
3076 int e = errno;
3077 close(ptmx_fd);
3078 errno = e;
3079 err(EXIT_FAILURE, "failed in unlockpt()");
3080 }
3081
3082 if (ioctl(ptmx_fd, TIOCGPTN, &index) < 0) {
3083 int e = errno;
3084 close(ptmx_fd);
3085 errno = e;
3086 err(EXIT_FAILURE, "failed in ioctl(TIOCGPTN)");
3087 }
3088
3089 pts = ptsname(ptmx_fd);
3090 if (pts == NULL) {
3091 int e = errno;
3092 close(ptmx_fd);
3093 errno = e;
3094 err(EXIT_FAILURE, "failed in ptsname()");
3095 }
3096
3097 if (ptmx_fd != fdescs[0].fd) {
3098 if (dup2(ptmx_fd, fdescs[0].fd) < 0) {
3099 int e = errno;
3100 close(ptmx_fd);
3101 errno = e;
3102 err(EXIT_FAILURE, "failed to dup %d -> %d", ptmx_fd, fdescs[0].fd);
3103 }
3104 close(ptmx_fd);
3105 ptmx_fd = fdescs[0].fd;
3106 }
3107
3108 pts_fd = open(pts, O_RDONLY);
3109 if (pts_fd < 0) {
3110 int e = errno;
3111 close(ptmx_fd);
3112 errno = e;
3113 err(EXIT_FAILURE, "failed in opening %s", pts);
3114 }
3115
3116 if (pts_fd != fdescs[1].fd) {
3117 if (dup2(pts_fd, fdescs[1].fd) < 0) {
3118 int e = errno;
3119 close(pts_fd);
3120 close(ptmx_fd);
3121 errno = e;
3122 err(EXIT_FAILURE, "failed to dup %d -> %d", pts_fd, fdescs[1].fd);
3123 }
3124 close(pts_fd);
3125 pts_fd = fdescs[1].fd;
3126 }
3127
3128 fdescs[0] = (struct fdesc){
3129 .fd = fdescs[0].fd,
3130 .close = close_fdesc,
3131 .data = NULL
3132 };
3133 fdescs[1] = (struct fdesc){
3134 .fd = fdescs[1].fd,
3135 .close = close_fdesc,
3136 .data = NULL
3137 };
3138
3139 indexp = xmalloc(sizeof(index));
3140 *indexp = index;
3141 return indexp;
3142 }
3143
3144 static void report_pty(const struct factory *factory _U_,
3145 int nth, void *data, FILE *fp)
3146 {
3147 if (nth == 0) {
3148 int *index = data;
3149 fprintf(fp, "%d", *index);
3150 }
3151 }
3152
3153 static void free_pty(const struct factory * factory _U_, void *data)
3154 {
3155 free(data);
3156 }
3157
3158 #define PARAM_END { .name = NULL, }
3159 static const struct factory factories[] = {
3160 {
3161 .name = "ro-regular-file",
3162 .desc = "read-only regular file",
3163 .priv = false,
3164 .N = 1,
3165 .EX_N = 0,
3166 .make = open_ro_regular_file,
3167 .params = (struct parameter []) {
3168 {
3169 .name = "file",
3170 .type = PTYPE_STRING,
3171 .desc = "file to be opened",
3172 .defv.string = "/etc/passwd",
3173 },
3174 {
3175 .name = "offset",
3176 .type = PTYPE_INTEGER,
3177 .desc = "seek bytes after open with SEEK_CUR",
3178 .defv.integer = 0,
3179 },
3180 {
3181 .name = "read-lease",
3182 .type = PTYPE_BOOLEAN,
3183 .desc = "taking out read lease for the file",
3184 .defv.boolean = false,
3185 },
3186 PARAM_END
3187 },
3188 },
3189 {
3190 .name = "make-regular-file",
3191 .desc = "regular file for writing",
3192 .priv = false,
3193 .N = 1,
3194 .EX_N = 0,
3195 .make = make_w_regular_file,
3196 .free = free_after_closing_duplicated_fd,
3197 .params = (struct parameter []) {
3198 {
3199 .name = "file",
3200 .type = PTYPE_STRING,
3201 .desc = "file to be made",
3202 .defv.string = "./test_mkfds_make_regular_file",
3203 },
3204 {
3205 .name = "delete",
3206 .type = PTYPE_BOOLEAN,
3207 .desc = "delete the file just after making it",
3208 .defv.boolean = false,
3209 },
3210 {
3211 .name = "write-bytes",
3212 .type = PTYPE_INTEGER,
3213 .desc = "write something (> 0)",
3214 .defv.integer = 0,
3215 },
3216 {
3217 .name = "readable",
3218 .type = PTYPE_BOOLEAN,
3219 .desc = "open the new file readable way",
3220 .defv.string = false,
3221 },
3222 {
3223 .name = "lock",
3224 .type = PTYPE_STRING,
3225 .desc = "the way for file locking: [none]|flock-sh|flock-ex|posix-r-|posix--w|posix-rw|ofd-r-|ofd--w|ofd-rw|lease-w",
3226 .defv.string = "none",
3227 },
3228 {
3229 .name = "dupfd",
3230 .type = PTYPE_INTEGER,
3231 .desc = "the number for the fd duplicated from the original fd",
3232 .defv.integer = -1,
3233 },
3234 PARAM_END
3235 },
3236 },
3237 {
3238 .name = "pipe-no-fork",
3239 .desc = "making pair of fds with pipe(2)",
3240 .priv = false,
3241 .N = 2,
3242 .EX_N = 2,
3243 .make = make_pipe,
3244 .params = (struct parameter []) {
3245 {
3246 .name = "nonblock",
3247 .type = PTYPE_STRING,
3248 .desc = "set nonblock flag (\"--\", \"r-\", \"-w\", or \"rw\")",
3249 .defv.string = "--",
3250 },
3251 {
3252 .name = "rdup",
3253 .type = PTYPE_INTEGER,
3254 .desc = "file descriptor for duplicating the pipe input",
3255 .defv.integer = -1,
3256 },
3257 {
3258 .name = "wdup",
3259 .type = PTYPE_INTEGER,
3260 .desc = "file descriptor for duplicating the pipe output",
3261 .defv.integer = -1,
3262 },
3263 PARAM_END
3264 },
3265 },
3266 {
3267 .name = "directory",
3268 .desc = "directory",
3269 .priv = false,
3270 .N = 1,
3271 .EX_N = 0,
3272 .make = open_directory,
3273 .params = (struct parameter []) {
3274 {
3275 .name = "dir",
3276 .type = PTYPE_STRING,
3277 .desc = "directory to be opened",
3278 .defv.string = "/",
3279 },
3280 {
3281 .name = "dentries",
3282 .type = PTYPE_INTEGER,
3283 .desc = "read the number of dentries after open with readdir(3)",
3284 .defv.integer = 0,
3285 },
3286 PARAM_END
3287 },
3288 },
3289 {
3290 .name = "rw-character-device",
3291 .desc = "character device with O_RDWR flag",
3292 .priv = false,
3293 .N = 1,
3294 .EX_N = 0,
3295 .make = open_rw_chrdev,
3296 .params = (struct parameter []) {
3297 {
3298 .name = "chrdev",
3299 .type = PTYPE_STRING,
3300 .desc = "character device node to be opened",
3301 .defv.string = "/dev/zero",
3302 },
3303 PARAM_END
3304 },
3305 },
3306 {
3307 .name = "socketpair",
3308 .desc = "AF_UNIX socket pair created with socketpair(2)",
3309 .priv = false,
3310 .N = 2,
3311 .EX_N = 0,
3312 .make = make_socketpair,
3313 .params = (struct parameter []) {
3314 {
3315 .name = "socktype",
3316 .type = PTYPE_STRING,
3317 .desc = "STREAM, DGRAM, or SEQPACKET",
3318 .defv.string = "STREAM",
3319 },
3320 {
3321 .name = "halfclose",
3322 .type = PTYPE_BOOLEAN,
3323 .desc = "Shutdown the read end of the 1st socket, the write end of the 2nd socket",
3324 .defv.boolean = false,
3325 },
3326 PARAM_END
3327 },
3328 },
3329 {
3330 .name = "symlink",
3331 .desc = "symbolic link itself opened with O_PATH",
3332 .priv = false,
3333 .N = 1,
3334 .EX_N = 0,
3335 .make = open_with_opath,
3336 .params = (struct parameter []) {
3337 {
3338 .name = "path",
3339 .type = PTYPE_STRING,
3340 .desc = "path to a symbolic link",
3341 .defv.string = "/dev/stdin",
3342 },
3343 PARAM_END
3344 },
3345 },
3346 {
3347 .name = "ro-block-device",
3348 .desc = "block device with O_RDONLY flag",
3349 .priv = true,
3350 .N = 1,
3351 .EX_N = 0,
3352 .make = open_ro_blkdev,
3353 .params = (struct parameter []) {
3354 {
3355 .name = "blkdev",
3356 .type = PTYPE_STRING,
3357 .desc = "block device node to be opened",
3358 .defv.string = "/dev/nullb0",
3359 },
3360 PARAM_END
3361 },
3362 },
3363 {
3364 .name = "mapped-packet-socket",
3365 .desc = "mmap'ed AF_PACKET socket",
3366 .priv = true,
3367 .N = 1,
3368 .EX_N = 0,
3369 .make = make_mmapped_packet_socket,
3370 .params = (struct parameter []) {
3371 {
3372 .name = "socktype",
3373 .type = PTYPE_STRING,
3374 .desc = "DGRAM or RAW",
3375 .defv.string = "RAW",
3376 },
3377 {
3378 .name = "interface",
3379 .type = PTYPE_STRING,
3380 .desc = "a name of network interface like eth0 or lo",
3381 .defv.string = "lo",
3382 },
3383 PARAM_END
3384 },
3385 },
3386 {
3387 .name = "pidfd",
3388 .desc = "pidfd returned from pidfd_open(2)",
3389 .priv = false,
3390 .N = 1,
3391 .EX_N = 0,
3392 .make = make_pidfd,
3393 .params = (struct parameter []) {
3394 {
3395 .name = "target-pid",
3396 .type = PTYPE_INTEGER,
3397 .desc = "the pid of the target process",
3398 .defv.integer = 1,
3399 },
3400 PARAM_END
3401 },
3402 },
3403 {
3404 .name = "inotify",
3405 .desc = "inotify fd returned from inotify_init(2)",
3406 .priv = false,
3407 .N = 1,
3408 .EX_N = 0,
3409 .make = make_inotify_fd,
3410 .params = (struct parameter []) {
3411 {
3412 .name = "dir",
3413 .type = PTYPE_STRING,
3414 .desc = "the directory that the inotify monitors",
3415 .defv.string = "/",
3416 },
3417 {
3418 .name = "file",
3419 .type = PTYPE_STRING,
3420 .desc = "the file that the inotify monitors",
3421 .defv.string = "/etc/fstab",
3422 },
3423 PARAM_END
3424 },
3425 },
3426 {
3427 .name = "unix-stream",
3428 .desc = "AF_UNIX+SOCK_STREAM sockets",
3429 .priv = false,
3430 .N = 3,
3431 .EX_N = 0,
3432 .make = make_unix_stream,
3433 .params = (struct parameter []) {
3434 {
3435 .name = "path",
3436 .type = PTYPE_STRING,
3437 .desc = "path for listening-socket bound to",
3438 .defv.string = "/tmp/test_mkfds-unix-stream",
3439 },
3440 {
3441 .name = "backlog",
3442 .type = PTYPE_INTEGER,
3443 .desc = "backlog passed to listen(2)",
3444 .defv.integer = 5,
3445 },
3446 {
3447 .name = "abstract",
3448 .type = PTYPE_BOOLEAN,
3449 .desc = "use PATH as an abstract socket address",
3450 .defv.boolean = false,
3451 },
3452 {
3453 .name = "server-shutdown",
3454 .type = PTYPE_INTEGER,
3455 .desc = "shutdown the accepted socket; 1: R, 2: W, 3: RW",
3456 .defv.integer = 0,
3457 },
3458 {
3459 .name = "client-shutdown",
3460 .type = PTYPE_INTEGER,
3461 .desc = "shutdown the client socket; 1: R, 2: W, 3: RW",
3462 .defv.integer = 0,
3463 },
3464 {
3465 .name = "type",
3466 .type = PTYPE_STRING,
3467 .desc = "stream or seqpacket",
3468 .defv.string = "stream",
3469 },
3470 PARAM_END
3471 },
3472 },
3473 {
3474 .name = "unix-dgram",
3475 .desc = "AF_UNIX+SOCK_DGRAM sockets",
3476 .priv = false,
3477 .N = 2,
3478 .EX_N = 0,
3479 .make = make_unix_dgram,
3480 .params = (struct parameter []) {
3481 {
3482 .name = "path",
3483 .type = PTYPE_STRING,
3484 .desc = "path for unix non-stream bound to",
3485 .defv.string = "/tmp/test_mkfds-unix-dgram",
3486 },
3487 {
3488 .name = "abstract",
3489 .type = PTYPE_BOOLEAN,
3490 .desc = "use PATH as an abstract socket address",
3491 .defv.boolean = false,
3492 },
3493 PARAM_END
3494 },
3495 },
3496 {
3497 .name = "unix-in-netns",
3498 .desc = "make a unix socket in a new network namespace",
3499 .priv = true,
3500 .N = 3,
3501 .EX_N = 0,
3502 .make = make_unix_in_new_netns,
3503 .params = (struct parameter []) {
3504 {
3505 .name = "type",
3506 .type = PTYPE_STRING,
3507 .desc = "dgram, stream, or seqpacket",
3508 .defv.string = "stream",
3509 },
3510 {
3511 .name = "path",
3512 .type = PTYPE_STRING,
3513 .desc = "path for unix non-stream bound to",
3514 .defv.string = "/tmp/test_mkfds-unix-in-netns",
3515 },
3516 {
3517 .name = "abstract",
3518 .type = PTYPE_BOOLEAN,
3519 .desc = "use PATH as an abstract socket address",
3520 .defv.boolean = false,
3521 },
3522 PARAM_END
3523 },
3524 },
3525 {
3526 .name = "tcp",
3527 .desc = "AF_INET+SOCK_STREAM sockets",
3528 .priv = false,
3529 .N = 3,
3530 .EX_N = 0,
3531 .make = make_tcp,
3532 .params = (struct parameter []) {
3533 {
3534 .name = "server-port",
3535 .type = PTYPE_INTEGER,
3536 .desc = "TCP port the server may listen",
3537 .defv.integer = 12345,
3538 },
3539 {
3540 .name = "client-port",
3541 .type = PTYPE_INTEGER,
3542 .desc = "TCP port the client may bind",
3543 .defv.integer = 23456,
3544 },
3545 PARAM_END
3546 }
3547 },
3548 {
3549 .name = "udp",
3550 .desc = "AF_INET+SOCK_DGRAM sockets",
3551 .priv = false,
3552 .N = 2,
3553 .EX_N = 0,
3554 .make = make_udp,
3555 .params = (struct parameter []) {
3556 {
3557 .name = "lite",
3558 .type = PTYPE_BOOLEAN,
3559 .desc = "Use UDPLITE instead of UDP",
3560 .defv.boolean = false,
3561 },
3562 {
3563 .name = "server-port",
3564 .type = PTYPE_INTEGER,
3565 .desc = "UDP port the server may listen",
3566 .defv.integer = 12345,
3567 },
3568 {
3569 .name = "client-port",
3570 .type = PTYPE_INTEGER,
3571 .desc = "UDP port the client may bind",
3572 .defv.integer = 23456,
3573 },
3574 {
3575 .name = "server-do-bind",
3576 .type = PTYPE_BOOLEAN,
3577 .desc = "call bind with the server socket",
3578 .defv.boolean = true,
3579 },
3580 {
3581 .name = "client-do-bind",
3582 .type = PTYPE_BOOLEAN,
3583 .desc = "call bind with the client socket",
3584 .defv.boolean = true,
3585 },
3586 {
3587 .name = "client-do-connect",
3588 .type = PTYPE_BOOLEAN,
3589 .desc = "call connect with the client socket",
3590 .defv.boolean = true,
3591 },
3592 PARAM_END
3593 }
3594 },
3595 {
3596 .name = "raw",
3597 .desc = "AF_INET+SOCK_RAW sockets",
3598 .priv = true,
3599 .N = 1,
3600 .EX_N = 0,
3601 .make = make_raw,
3602 .params = (struct parameter []) {
3603 {
3604 .name = "protocol",
3605 .type = PTYPE_INTEGER,
3606 .desc = "protocol passed to socket(AF_INET, SOCK_RAW, protocol)",
3607 .defv.integer = IPPROTO_IPIP,
3608 },
3609 PARAM_END
3610 }
3611
3612 },
3613 {
3614 .name = "ping",
3615 .desc = "AF_INET+SOCK_DGRAM+IPPROTO_ICMP sockets",
3616 .priv = false,
3617 .N = 1,
3618 .EX_N = 0,
3619 .make = make_ping,
3620 .params = (struct parameter []) {
3621 {
3622 .name = "connect",
3623 .type = PTYPE_BOOLEAN,
3624 .desc = "call connect(2) with the socket",
3625 .defv.boolean = true,
3626 },
3627 {
3628 .name = "bind",
3629 .type = PTYPE_BOOLEAN,
3630 .desc = "call bind(2) with the socket",
3631 .defv.boolean = true,
3632 },
3633 {
3634 .name = "id",
3635 .type = PTYPE_INTEGER,
3636 .desc = "ICMP echo request id",
3637 .defv.integer = 0,
3638 },
3639 PARAM_END
3640 }
3641 },
3642 {
3643 .name = "tcp6",
3644 .desc = "AF_INET6+SOCK_STREAM sockets",
3645 .priv = false,
3646 .N = 3,
3647 .EX_N = 0,
3648 .make = make_tcp6,
3649 .params = (struct parameter []) {
3650 {
3651 .name = "server-port",
3652 .type = PTYPE_INTEGER,
3653 .desc = "TCP port the server may listen",
3654 .defv.integer = 12345,
3655 },
3656 {
3657 .name = "client-port",
3658 .type = PTYPE_INTEGER,
3659 .desc = "TCP port the client may bind",
3660 .defv.integer = 23456,
3661 },
3662 PARAM_END
3663 }
3664 },
3665 {
3666 .name = "udp6",
3667 .desc = "AF_INET6+SOCK_DGRAM sockets",
3668 .priv = false,
3669 .N = 2,
3670 .EX_N = 0,
3671 .make = make_udp6,
3672 .params = (struct parameter []) {
3673 {
3674 .name = "lite",
3675 .type = PTYPE_BOOLEAN,
3676 .desc = "Use UDPLITE instead of UDP",
3677 .defv.boolean = false,
3678 },
3679 {
3680 .name = "server-port",
3681 .type = PTYPE_INTEGER,
3682 .desc = "UDP port the server may listen",
3683 .defv.integer = 12345,
3684 },
3685 {
3686 .name = "client-port",
3687 .type = PTYPE_INTEGER,
3688 .desc = "UDP port the client may bind",
3689 .defv.integer = 23456,
3690 },
3691 {
3692 .name = "server-do-bind",
3693 .type = PTYPE_BOOLEAN,
3694 .desc = "call bind with the server socket",
3695 .defv.boolean = true,
3696 },
3697 {
3698 .name = "client-do-bind",
3699 .type = PTYPE_BOOLEAN,
3700 .desc = "call bind with the client socket",
3701 .defv.boolean = true,
3702 },
3703 {
3704 .name = "client-do-connect",
3705 .type = PTYPE_BOOLEAN,
3706 .desc = "call connect with the client socket",
3707 .defv.boolean = true,
3708 },
3709 PARAM_END
3710 }
3711 },
3712 {
3713 .name = "raw6",
3714 .desc = "AF_INET6+SOCK_RAW sockets",
3715 .priv = true,
3716 .N = 1,
3717 .EX_N = 0,
3718 .make = make_raw6,
3719 .params = (struct parameter []) {
3720 {
3721 .name = "protocol",
3722 .type = PTYPE_INTEGER,
3723 .desc = "protocol passed to socket(AF_INET6, SOCK_RAW, protocol)",
3724 .defv.integer = IPPROTO_IPIP,
3725 },
3726 PARAM_END
3727 }
3728
3729 },
3730 {
3731 .name = "ping6",
3732 .desc = "AF_INET6+SOCK_DGRAM+IPPROTO_ICMPV6 sockets",
3733 .priv = false,
3734 .N = 1,
3735 .EX_N = 0,
3736 .make = make_ping6,
3737 .params = (struct parameter []) {
3738 {
3739 .name = "connect",
3740 .type = PTYPE_BOOLEAN,
3741 .desc = "call connect(2) with the socket",
3742 .defv.boolean = true,
3743 },
3744 {
3745 .name = "bind",
3746 .type = PTYPE_BOOLEAN,
3747 .desc = "call bind(2) with the socket",
3748 .defv.boolean = true,
3749 },
3750 {
3751 .name = "id",
3752 .type = PTYPE_INTEGER,
3753 .desc = "ICMP echo request id",
3754 .defv.integer = 0,
3755 },
3756 PARAM_END
3757 }
3758 },
3759 {
3760 .name = "netns",
3761 .desc = "open a file specifying a netns",
3762 .priv = true,
3763 .N = 1,
3764 .EX_N = 0,
3765 .make = make_netns,
3766 .params = (struct parameter []) {
3767 PARAM_END
3768 }
3769 },
3770 {
3771 .name = "netlink",
3772 .desc = "AF_NETLINK sockets",
3773 .priv = false,
3774 .N = 1,
3775 .EX_N = 0,
3776 .make = make_netlink,
3777 .params = (struct parameter []) {
3778 {
3779 .name = "protocol",
3780 .type = PTYPE_INTEGER,
3781 .desc = "protocol passed to socket(AF_NETLINK, SOCK_RAW, protocol)",
3782 .defv.integer = NETLINK_USERSOCK,
3783 },
3784 {
3785 .name = "groups",
3786 .type = PTYPE_UINTEGER,
3787 .desc = "multicast groups of netlink communication (requires CAP_NET_ADMIN)",
3788 .defv.uinteger = 0,
3789 },
3790 PARAM_END
3791 }
3792 },
3793 {
3794 .name = "eventfd",
3795 .desc = "make an eventfd connecting two processes",
3796 .priv = false,
3797 .N = 2,
3798 .EX_N = 0,
3799 .EX_R = 1,
3800 .make = make_eventfd,
3801 .report = report_eventfd,
3802 .free = free_eventfd,
3803 .params = (struct parameter []) {
3804 PARAM_END
3805 }
3806 },
3807 {
3808 .name = "mqueue",
3809 .desc = "make a mqueue connecting two processes",
3810 .priv = false,
3811 .N = 2,
3812 .EX_N = 0,
3813 .EX_R = 1,
3814 .make = make_mqueue,
3815 .report = report_mqueue,
3816 .free = free_mqueue,
3817 .params = (struct parameter []) {
3818 {
3819 .name = "path",
3820 .type = PTYPE_STRING,
3821 .desc = "path for mqueue",
3822 .defv.string = "/test_mkfds-mqueue",
3823 },
3824 PARAM_END
3825 }
3826 },
3827 {
3828 .name = "sysvshm",
3829 .desc = "shared memory mapped with SYSVIPC shmem syscalls",
3830 .priv = false,
3831 .N = 0,
3832 .EX_N = 0,
3833 .make = make_sysvshm,
3834 .free = free_sysvshm,
3835 .params = (struct parameter []) {
3836 PARAM_END
3837 },
3838 },
3839 {
3840 .name = "eventpoll",
3841 .desc = "make eventpoll (epoll) file",
3842 .priv = false,
3843 .N = 3,
3844 .EX_N = 0,
3845 .make = make_eventpoll,
3846 .params = (struct parameter []) {
3847 PARAM_END
3848 }
3849 },
3850 {
3851 .name = "timerfd",
3852 .desc = "make timerfd",
3853 .priv = false,
3854 .N = 1,
3855 .EX_N = 0,
3856 .make = make_timerfd,
3857 .params = (struct parameter []) {
3858 {
3859 .name = "clockid",
3860 .type = PTYPE_STRING,
3861 .desc = "ID: realtime, monotonic, boottime, realtime-alarm, or boottime-alarm",
3862 .defv.string = "realtime",
3863 },
3864 {
3865 .name = "abstime",
3866 .type = PTYPE_BOOLEAN,
3867 .desc = "use TFD_TIMER_ABSTIME flag",
3868 .defv.boolean = false,
3869 },
3870 {
3871 .name = "remaining",
3872 .type = PTYPE_UINTEGER,
3873 .desc = "remaining seconds for expiration",
3874 .defv.uinteger = 99,
3875 },
3876 {
3877 .name = "interval",
3878 .type = PTYPE_UINTEGER,
3879 .desc = "inteval in seconds",
3880 .defv.uinteger = 10,
3881 },
3882 {
3883 .name = "interval-nanofrac",
3884 .type = PTYPE_UINTEGER,
3885 .desc = "nsec part of inteval",
3886 .defv.uinteger = 0,
3887 },
3888
3889 PARAM_END
3890 }
3891 },
3892 {
3893 .name = "signalfd",
3894 .desc = "make signalfd",
3895 .priv = false,
3896 .N = 1,
3897 .EX_N = 0,
3898 .make = make_signalfd,
3899 .params = (struct parameter []) {
3900 PARAM_END
3901 }
3902 },
3903 {
3904 .name = "cdev-tun",
3905 .desc = "open /dev/net/tun",
3906 .priv = true,
3907 .N = 1,
3908 .EX_N = 0,
3909 .EX_R = 1,
3910 .make = make_cdev_tun,
3911 .report = report_cdev_tun,
3912 .free = free_cdev_tun,
3913 .params = (struct parameter []) {
3914 PARAM_END
3915 }
3916 },
3917 {
3918 .name = "bpf-prog",
3919 .desc = "make bpf-prog",
3920 .priv = true,
3921 .N = 1,
3922 .EX_N = 0,
3923 .make = make_bpf_prog,
3924 .params = (struct parameter []) {
3925 {
3926 .name = "prog-type-id",
3927 .type = PTYPE_INTEGER,
3928 .desc = "program type by id",
3929 .defv.integer = 1,
3930 },
3931 {
3932 .name = "name",
3933 .type = PTYPE_STRING,
3934 .desc = "name assigned to bpf prog object",
3935 .defv.string = "mkfds_bpf_prog",
3936 },
3937 PARAM_END
3938 }
3939 },
3940 {
3941 .name = "multiplexing",
3942 .desc = "making pipes monitored by multiplexers",
3943 .priv = false,
3944 .N = 12,
3945 .EX_N = 0,
3946 .make = make_some_pipes,
3947 .params = (struct parameter []) {
3948 PARAM_END
3949 }
3950 },
3951 {
3952 .name = "bpf-map",
3953 .desc = "make bpf-map",
3954 .priv = true,
3955 .N = 1,
3956 .EX_N = 0,
3957 .make = make_bpf_map,
3958 .params = (struct parameter []) {
3959 {
3960 .name = "map-type-id",
3961 .type = PTYPE_INTEGER,
3962 .desc = "map type by id",
3963 .defv.integer = 1,
3964 },
3965 {
3966 .name = "name",
3967 .type = PTYPE_STRING,
3968 .desc = "name assigned to the bpf map object",
3969 .defv.string = "mkfds_bpf_map",
3970 },
3971 PARAM_END
3972 }
3973 },
3974 {
3975 .name = "pty",
3976 .desc = "make a pair of ptmx and pts",
3977 .priv = false,
3978 .N = 2,
3979 .EX_N = 0,
3980 .EX_R = 1,
3981 .make = make_pty,
3982 .report = report_pty,
3983 .free = free_pty,
3984 .params = (struct parameter []) {
3985 PARAM_END
3986 }
3987 },
3988 };
3989
3990 static int count_parameters(const struct factory *factory)
3991 {
3992
3993 const struct parameter *p = factory->params;
3994 if (!p)
3995 return 0;
3996 while (p->name)
3997 p++;
3998 return p - factory->params;
3999 }
4000
4001 static void print_factory(const struct factory *factory)
4002 {
4003 printf("%-20s %4s %5d %7d %6d %s\n",
4004 factory->name,
4005 factory->priv? "yes": "no",
4006 factory->N,
4007 factory->EX_R + 1,
4008 count_parameters(factory),
4009 factory->desc);
4010 }
4011
4012 static void list_factories(void)
4013 {
4014 printf("%-20s PRIV COUNT NRETURN NPARAM DESCRIPTION\n", "FACTORY");
4015 for (size_t i = 0; i < ARRAY_SIZE(factories); i++)
4016 print_factory(factories + i);
4017 }
4018
4019 static const struct factory *find_factory(const char *name)
4020 {
4021 for (size_t i = 0; i < ARRAY_SIZE(factories); i++)
4022 if (strcmp(factories[i].name, name) == 0)
4023 return factories + i;
4024 return NULL;
4025 }
4026
4027 static void list_parameters(const char *factory_name)
4028 {
4029 const struct factory *factory = find_factory(factory_name);
4030 const char *fmt = "%-15s %-8s %15s %s\n";
4031
4032 if (!factory)
4033 errx(EXIT_FAILURE, "no such factory: %s", factory_name);
4034
4035 if (!factory->params)
4036 return;
4037
4038 printf(fmt, "PARAMETER", "TYPE", "DEFAULT_VALUE", "DESCRIPTION");
4039 for (const struct parameter *p = factory->params; p->name != NULL; p++) {
4040 char *defv = ptype_classes[p->type].sprint(&p->defv);
4041 printf(fmt, p->name, ptype_classes[p->type].name, defv, p->desc);
4042 free(defv);
4043 }
4044 }
4045
4046 static void rename_self(const char *comm)
4047 {
4048 if (prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0) < 0)
4049 err(EXIT_FAILURE, "failed to rename self via prctl: %s", comm);
4050 }
4051
4052 static void do_nothing(int signum _U_)
4053 {
4054 }
4055
4056 #ifdef __NR_pidfd_open
4057
4058 static int
4059 pidfd_open(pid_t pid, unsigned int flags)
4060 {
4061 return syscall(__NR_pidfd_open, pid, flags);
4062 }
4063 #else
4064 static int
4065 pidfd_open(pid_t pid _U_, unsigned int flags _U_)
4066 {
4067 errno = ENOSYS;
4068 return -1;
4069 }
4070 #endif
4071
4072 /*
4073 * Multiplexers
4074 */
4075 struct multiplexer {
4076 const char *name;
4077 void (*fn)(bool, struct fdesc *fdescs, size_t n_fdescs);
4078 };
4079
4080 #if defined(__NR_select) || defined(__NR_poll)
4081 static void sighandler_nop(int si _U_)
4082 {
4083 /* Do nothing */
4084 }
4085 #endif
4086
4087 #define DEFUN_WAIT_EVENT_SELECT(NAME,SYSCALL,XDECLS,SETUP_SIG_HANDLER,SYSCALL_INVOCATION) \
4088 static void wait_event_##NAME(bool add_stdin, struct fdesc *fdescs, size_t n_fdescs) \
4089 { \
4090 fd_set readfds; \
4091 fd_set writefds; \
4092 fd_set exceptfds; \
4093 XDECLS \
4094 int n = 0; \
4095 \
4096 FD_ZERO(&readfds); \
4097 FD_ZERO(&writefds); \
4098 FD_ZERO(&exceptfds); \
4099 /* Monitor the standard input only when the process \
4100 * is in foreground. */ \
4101 if (add_stdin) { \
4102 n = 1; \
4103 FD_SET(0, &readfds); \
4104 } \
4105 \
4106 for (size_t i = 0; i < n_fdescs; i++) { \
4107 if (fdescs[i].mx_modes & MX_READ) { \
4108 n = max(n, fdescs[i].fd + 1); \
4109 FD_SET(fdescs[i].fd, &readfds); \
4110 } \
4111 if (fdescs[i].mx_modes & MX_WRITE) { \
4112 n = max(n, fdescs[i].fd + 1); \
4113 FD_SET(fdescs[i].fd, &writefds); \
4114 } \
4115 if (fdescs[i].mx_modes & MX_EXCEPT) { \
4116 n = max(n, fdescs[i].fd + 1); \
4117 FD_SET(fdescs[i].fd, &exceptfds); \
4118 } \
4119 } \
4120 \
4121 SETUP_SIG_HANDLER \
4122 \
4123 if (SYSCALL_INVOCATION < 0 \
4124 && errno != EINTR) \
4125 err(EXIT_FAILURE, "failed in " SYSCALL); \
4126 }
4127
4128 DEFUN_WAIT_EVENT_SELECT(default,
4129 "pselect",
4130 sigset_t sigset;,
4131 sigemptyset(&sigset);,
4132 pselect(n, &readfds, &writefds, &exceptfds, NULL, &sigset))
4133
4134 #ifdef __NR_pselect6
4135 DEFUN_WAIT_EVENT_SELECT(pselect6,
4136 "pselect6",
4137 sigset_t sigset;,
4138 sigemptyset(&sigset);,
4139 syscall(__NR_pselect6, n, &readfds, &writefds, &exceptfds, NULL, &sigset))
4140 #endif
4141
4142 #ifdef __NR_select
4143 DEFUN_WAIT_EVENT_SELECT(select,
4144 "select",
4145 ,
4146 signal(SIGCONT,sighandler_nop);,
4147 syscall(__NR_select, n, &readfds, &writefds, &exceptfds, NULL))
4148 #endif
4149
4150 #ifdef __NR_poll
4151 static DEFUN_WAIT_EVENT_POLL(poll,
4152 "poll",
4153 ,
4154 signal(SIGCONT,sighandler_nop);,
4155 syscall(__NR_poll, pfds, n, -1))
4156 #endif
4157
4158 #define DEFAULT_MULTIPLEXER 0
4159 static struct multiplexer multiplexers [] = {
4160 {
4161 .name = "default",
4162 .fn = wait_event_default,
4163 },
4164 #ifdef __NR_pselect6
4165 {
4166 .name = "pselect6",
4167 .fn = wait_event_pselect6,
4168 },
4169 #endif
4170 #ifdef __NR_select
4171 {
4172 .name = "select",
4173 .fn = wait_event_select,
4174 },
4175 #endif
4176 #ifdef __NR_poll
4177 {
4178 .name = "poll",
4179 .fn = wait_event_poll,
4180 },
4181 #endif
4182 #ifdef __NR_ppoll
4183 {
4184 .name = "ppoll",
4185 .fn = wait_event_ppoll,
4186 },
4187 #endif
4188 };
4189
4190 static struct multiplexer *lookup_multiplexer(const char *name)
4191 {
4192 for (size_t i = 0; i < ARRAY_SIZE(multiplexers); i++)
4193 if (strcmp(name, multiplexers[i].name) == 0)
4194 return multiplexers + i;
4195 return NULL;
4196 }
4197
4198 static void list_multiplexers(void)
4199 {
4200 puts("NAME");
4201 for (size_t i = 0; i < ARRAY_SIZE(multiplexers); i++)
4202 puts(multiplexers[i].name);
4203 }
4204
4205 int main(int argc, char **argv)
4206 {
4207 int c;
4208 const struct factory *factory;
4209 struct fdesc fdescs[MAX_N];
4210 bool quiet = false;
4211 bool cont = false;
4212 void *data;
4213 bool monitor_stdin = true;
4214
4215 struct multiplexer *wait_event = NULL;
4216
4217 static const struct option longopts[] = {
4218 { "list", no_argument, NULL, 'l' },
4219 { "parameters", required_argument, NULL, 'I' },
4220 { "comm", required_argument, NULL, 'r' },
4221 { "quiet", no_argument, NULL, 'q' },
4222 { "dont-monitor-stdin", no_argument, NULL, 'X' },
4223 { "dont-puase", no_argument, NULL, 'c' },
4224 { "wait-with", required_argument, NULL, 'w' },
4225 { "multiplexers",no_argument,NULL, 'W' },
4226 { "help", no_argument, NULL, 'h' },
4227 { NULL, 0, NULL, 0 },
4228 };
4229
4230 while ((c = getopt_long(argc, argv, "lhqcI:r:w:WX", longopts, NULL)) != -1) {
4231 switch (c) {
4232 case 'h':
4233 usage(stdout, EXIT_SUCCESS);
4234 case 'l':
4235 list_factories();
4236 exit(EXIT_SUCCESS);
4237 case 'I':
4238 list_parameters(optarg);
4239 exit(EXIT_SUCCESS);
4240 case 'q':
4241 quiet = true;
4242 break;
4243 case 'c':
4244 cont = true;
4245 break;
4246 case 'w':
4247 wait_event = lookup_multiplexer(optarg);
4248 if (wait_event == NULL)
4249 errx(EXIT_FAILURE, "unknown multiplexer: %s", optarg);
4250 break;
4251 case 'W':
4252 list_multiplexers();
4253 exit(EXIT_SUCCESS);
4254 case 'r':
4255 rename_self(optarg);
4256 break;
4257 case 'X':
4258 monitor_stdin = false;
4259 break;
4260 default:
4261 usage(stderr, EXIT_FAILURE);
4262 }
4263 }
4264
4265 if (optind == argc)
4266 errx(EXIT_FAILURE, "no file descriptor specification given");
4267
4268 if (cont && wait_event)
4269 errx(EXIT_FAILURE, "don't specify both -c/--dont-puase and -w/--wait-with options");
4270 if (wait_event == NULL)
4271 wait_event = multiplexers + DEFAULT_MULTIPLEXER;
4272
4273 factory = find_factory(argv[optind]);
4274 if (!factory)
4275 errx(EXIT_FAILURE, "no such factory: %s", argv[optind]);
4276 assert(factory->N + factory->EX_N < MAX_N);
4277 optind++;
4278
4279 if ((optind + factory->N) > argc)
4280 errx(EXIT_FAILURE, "not enough file descriptors given for %s",
4281 factory->name);
4282
4283 if (factory->priv && getuid() != 0)
4284 errx(EXIT_FAILURE, "%s factory requires root privilege", factory->name);
4285
4286 for (int i = 0; i < MAX_N; i++) {
4287 fdescs[i].fd = -1;
4288 fdescs[i].mx_modes = 0;
4289 fdescs[i].close = NULL;
4290 }
4291
4292 for (int i = 0; i < factory->N; i++) {
4293 char *str = argv[optind + i];
4294 long fd;
4295 char *ep;
4296
4297 errno = 0;
4298 fd = strtol(str, &ep, 10);
4299 if (errno)
4300 err(EXIT_FAILURE, "failed to convert fd number: %s", str);
4301 if (ep == str)
4302 errx(EXIT_FAILURE, "failed to convert fd number: %s", str);
4303 if (*ep != '\0')
4304 errx(EXIT_FAILURE, "garbage at the end of number: %s", str);
4305 if (fd < 0)
4306 errx(EXIT_FAILURE, "fd number should not be negative: %s", str);
4307 if (fd < 3)
4308 errx(EXIT_FAILURE, "fd 0, 1, 2 are reserved: %s", str);
4309 fdescs[i].fd = fd;
4310 }
4311 optind += factory->N;
4312
4313 data = factory->make(factory, fdescs, argc - optind, argv + optind);
4314
4315 signal(SIGCONT, do_nothing);
4316
4317 if (!quiet) {
4318 printf("%d", getpid());
4319 if (factory->report) {
4320 for (int i = 0; i < factory->EX_R; i++) {
4321 putchar(' ');
4322 factory->report(factory, i, data, stdout);
4323 }
4324 }
4325 putchar('\n');
4326 fflush(stdout);
4327 }
4328
4329 if (!cont)
4330 wait_event->fn(monitor_stdin,
4331 fdescs, factory->N + factory->EX_N);
4332
4333 for (int i = 0; i < factory->N + factory->EX_N; i++)
4334 if (fdescs[i].fd >= 0 && fdescs[i].close)
4335 fdescs[i].close(fdescs[i].fd, fdescs[i].data);
4336
4337 if (factory->free)
4338 factory->free (factory, data);
4339
4340 exit(EXIT_SUCCESS);
4341 }