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