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