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