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